我有一个共享状态的组件,需要同步。
一段状态设置了当前的音阶类型,它应该支持所有可能的音阶,但我从小调和大调开始。第二个状态根据所选的刻度类型为所选的音符名称设置正确的音符。我让它大部分工作,但我需要更好地同步状态,这样一个可以对另一个做出反应。
react社区的一些人建议"提升国家",我正试图弄清楚如何正确地做到这一点,尤其是使用钩子。
因此,我已经能够弄清楚如何将组件上设置的音阶音符的状态提升到一些充满数组的对象中,但现在我需要弄清楚如何提升以下代码中的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道具中的箭头功能"提升"到它自己的功能中,但我不知道如何进行,因为要求是我需要将不同的状态传递给该功能的每个实例,但要使该状态与另一个状态同步,即设置音符按钮然后反应的刻度类型。
更新:
经过仔细检查,我认为状态功能如下:
Scale Type
|
|
| Root Note
| /
| /
Scale Notes
其中刻度类型将影响选择的根音符(例如C#或Db(以及刻度本身的音符。然后,音阶音符还需要知道根音符与音阶类型的组合。
根据我从您的问题中了解到的情况,您的状态中有以下依赖项-
Root Note Scale
/
/
Notes
仅当root note name (c/d/e etc)
或scale (major/minor etc)
发生变化时,notes
状态变量才会发生变化。您可以将所有与比例相关的状态抽象到上下文中,并在相应的组件中使用它,如下所示。您可以使用useEffect
钩子的第二个arg来侦听状态变量的更改并执行副作用。
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&隐藏导航=1&主题=深色