【问题标题】:How do I 'lift up' a setState function in a react component using hooks?如何使用钩子“提升”反应组件中的 setState 函数?
【发布时间】:2020-06-03 08:41:21
【问题描述】:

我有一个需要同步的共享状态组件。

一个状态设置当前的音阶类型,它应该支持所有可能的音阶,但我从小调和大调开始。第二个状态根据所选的音阶类型为所选音符名称设置正确的音符。我大部分时间都在工作,但我需要更好地同步状态,以便一个人可以对另一个人做出反应。

react 社区中的一些人建议“提升状态”,我正试图弄清楚如何正确地做到这一点,尤其是使用钩子。

所以,我已经能够弄清楚如何将设置在组件上的音阶音符的状态提升到一些充满数组的对象中,但现在我需要弄清楚如何提升 @下面代码中的987654321@函数,有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 道具中的箭头函数“提升”到它自己的函数中,但我不知道如何去做,因为要求是我需要传递不同的状态到函数的每个实例,但保持该状态与另一个状态同步,这是设置音符按钮然后反应的比例类型。

更新:

经过仔细检查,我认为状态功能如下:

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

...其中音阶类型将影响选择的根音(例如 C# 或 Db)以及音阶本身的音符。那么音阶音符还需要结合音阶类型知道根音。

【问题讨论】:

  • ` onClick = () => { } `你可以像这样传递箭头函数。

标签: reactjs react-hooks


【解决方案1】:

根据我从您的问题中了解到的情况,您的状态具有以下依赖项-

Root Note       Scale
        \       /
         \     /
          Notes

notes 状态变量仅在root note name (c/d/e etc) 或scale (major/minor etc) 发生更改时更改。您可以将所有与比例相关的状态抽象到一个上下文中,并在相应的组件中使用它,如下所示。您可以使用useEffect 钩子的第二个参数来监听状态变量的变化并执行side-effects。

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);

App.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

【讨论】:

  • hmmmm...Dan Abramov 在 twitter 上提出了一个类似的建议,除了最后一个问题外,它大部分都有效...我认为我的状态实际上有点复杂,因为规模会影响两者根音和音阶音符和音阶都受两者的影响。这样做的原因是,有时根音需要根据音阶类型进行更改...例如,如果音阶大于 1,则使用“Db”,但如果音阶较小,则正确的根音为“C#” ...所以我想我需要提升根音,但我仍然需要更改它们以设置音阶音符...希望这是有道理的...
  • 这里是一个 dan 制作和分叉的沙箱的链接......它几乎就在那里,即使没有 useEffect 或上下文,除了根也取决于比例类型,所以当用户选择Db major 然后切换到C# minor,注释不会自动更新,而是用户必须重新单击选定的按钮才能看到次要注释,这不是预期的效果......太接近了,tho! ! XD......codesandbox.io/s/keez-beez-switchingalmost-2ikvs
  • 我更新了问题以反映我对状态及其交互的新理解。
  • 很高兴您能够识别覆盖您的用例的状态交互,我只想传达您应该将所有相互依赖的状态抽象到上下文和使用端-效果在一个地方,你还需要注意你的状态变量之间的循环依赖。
  • hmmm..好吧,您对我如何能够处理这种更复杂的状态关系有任何想法吗?你认为我需要开始研究类似 useReducer 的东西吗?
猜你喜欢
  • 2021-05-26
  • 1970-01-01
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 2020-12-31
相关资源
最近更新 更多