Как «поднять» функцию setState в реагирующем компоненте, используя хуки? - PullRequest
0 голосов
/ 19 февраля 2020

У меня есть компонент с общим состоянием, который должен быть синхронизирован c.

Одна часть состояния устанавливает текущий тип музыкальной шкалы, который должен поддерживать все возможные масштабы, но я начинаю с несовершеннолетним и основным. Вторая часть состояния устанавливает правильные примечания для выбранного имени примечания, основанного на выбранном типе масштаба. У меня это в основном работает, но мне нужно лучше синхронизировать состояние, чтобы один мог реагировать на другое.

Несколько человек в сообществе реагирования рекомендовали «поднять состояние», что Я пытаюсь понять, как это сделать правильно, особенно с помощью хуков.

Итак, я смог выяснить, как поднять состояние нот музыкальной гаммы, которое было установлено на компонентах, в некоторые объекты, заполненные массивами, но теперь мне нужно выяснить, как поднять функцию onClick в следующем коде, и есть 12 из этих компонентов имен нот, и каждый из них устанавливает различные музыкальные масштабы в состояние notes :

<NoteInput
  id="c"
  scale={scale}
  type="radio"
  name="notes"
  label="c"
  value="c"
  onClick={
    () => setNotes(
      scale === 'minor' ? scalePatterns['c-minor'] :
      scale === 'major' ? scalePatterns['c-major'] :
      ''
    )
  }
/>
<NoteLabel
  whileHover={{ scale: 1 }}
  whileTap={{ scale: 0.9 }}
  scale={scale}
  htmlFor="c"
>
  {
    scale === 'major' ? 'C' :
    scale === 'minor' ? 'C' :
    'C'
  }
</NoteLabel>

Так что теперь мне нужно выяснить, как «поднять» функцию стрелки в подпорке onClick в ее собственную функцию, но я не знаю, как это сделать go, так как требование заключается в том, что мне нужно передавать разные состояния каждому экземпляру функции, но поддерживать это состояние в синхронизации c с другим фрагментом состояния, который устанавливает sc Укажите, на что затем реагируют кнопки примечания.

ОБНОВЛЕНИЕ:

При ближайшем рассмотрении я считаю, что состояние работает следующим образом:

Scale Type
  |     \
  |      \ 
  |    Root Note
  |      /
  |     /
Scale Notes

... где Тип шкалы влияет как на выбранную ноту root (например, C# или Db), так и на ноты для самой шкалы. Тогда примечаниям шкалы ТАКЖЕ нужно знать примечание root в сочетании с типом шкалы.

1 Ответ

0 голосов
/ 20 февраля 2020

Исходя из того, что я понял из вашего вопроса, у вас есть следующие зависимости в вашем состоянии -

Root Note       Scale
        \       /
         \     /
          Notes

Переменная состояния notes изменяется только при изменении либо root note name (c/d/e etc), либо scale (major/minor etc). Вы можете абстрагировать все связанное с масштабированием состояние в контекст и использовать его в соответствующем компоненте, как показано ниже. Вы можете использовать 2-й аргумент крюка useEffect для прослушивания изменений переменных состояния и выполнения побочных эффектов .

ScalesContext. js

...

const SCALE_PATTERNS = {
  "c-major": ["c", "d", "e", "f", "g", "a", "b"],
  "c-minor": ["c", "d", "eflat", "f", "g", "aflat", "bflat"]
};

const ScalesContext = createContext(null);

export const ScalesContextProvider = ({ children }) => {
  const [rootNote, setRootNote] = useState(""); // 'c'
  const [scale, setScale] = useState(""); // 'major'
  const [notes, setNotes] = useState([]); // ['c', 'd', ...]

  // On scale/rootNote state change -> update notes
  useEffect(() => {
    const key = `${rootNote}-${scale}`;
    setNotes(SCALE_PATTERNS[key]);
  }, [scale, rootNote]);

  return (
    <ScalesContext.Provider
      value={{ rootNote, scale, notes, setScale, setRootNote }}
    >
      {children}
    </ScalesContext.Provider>
  );
};

export const useScalesContext = () => useContext(ScalesContext);

Приложение. js

...

export default function App() {
  return (
    <div className="App">
      // Hook up Provider around ScaleSelect component
      <ScalesContextProvider>
        <ScaleSelect />
      </ScalesContextProvider>
    </div>
  );
}

ScaleSelect. js

...

export const ScaleSelect = () => {
  const state = useScalesContext();
  const { rootNote, scale, notes, setScale, setRootNote } = state;

  return (
    <div>
      <p>Root Note: {rootNote}</p>
      <p>Scale: {scale}</p>
      <input
        type="text"
        value={rootNote}
        placeholder="Root Note (try 'c')"
        onChange={e => setRootNote(e.target.value)}
      />
      <input
        type="text"
        placeholder="Scale (try 'major')"
        value={scale}
        onChange={e => setScale(e.target.value)}
      />
      <p>Notes: {JSON.stringify(notes)}</p>
    </div>
  );
};

У меня есть рабочий пример здесь - https://codesandbox.io/s/scales-notes-d8o18?fontsize=14&hidenavigation=1&theme=dark

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...