我有一个具有多种选择的react组件。我为每个选择都关联了一个快捷方式。为此,我使用了“ react-hotkeys-hook”。
因此答案第一个答案具有快捷方式1,第二个答案具有答案2,依此类推。
问题是,回答后,我更新了视图以显示另一个可以选择不同数量的问题。这使钩子爆炸了,因为钩子的数量因渲染而异。
// sort of pseudo-code
const comp = () => {
for(let i=1; i < 6; i++) {
useHotKey(i, callback, [dependencies])
}
return (
<>
<choice/>
<choice/>
</>
)
}
我将如何实施呢?目前,我默认情况下只创建5个快捷键,但是我希望不要对键盘快捷键的数量进行硬编码。
答案 0 :(得分:3)
由于Rules of Hooks,您无法动态调用钩子,更好的方法是使用composition。
您的Choice
组件应该有一个hotKey
和callback
道具,父母应该决定选择的数量。
const Choice = ({ hotKey, callback }) => {
useHotKey(hotKey, callback);
return <>...</>;
};
// Usages
<Choice hotKey="1" callback={()=>console.log('1')} />
choices.map((_,index) => <Choice key={index} hotKey={index} ... />);
答案 1 :(得分:3)
也许以下示例可以为您提供帮助:
const useHotKey = (keys, callback) => {
React.useEffect(() => {
const keyUp = (e) => {
if (keys.includes(e.key)) {
callback(e.key);
}
};
document.body.addEventListener('keyup', keyUp);
return () =>
document.body.removeEventListener('keyup', keyUp);
}, [callback, keys]); //callback never chanes but keys does
};
const questions = [
['1', '2', '3', '4'],
['1', '2'],
['1', '2', '3'],
['a', 'b', 'c'],
];
const Answer = ({ answers, answer }) => {
useHotKey(answers, answer);
return <pre>ansers:{JSON.stringify(answers)}</pre>;
};
const App = () => {
const [current, setCurrent] = React.useState(0);
const [answers, setAnswers] = React.useState([]);
//answer is the callback but never changes because
// there are no dependencies
const answer = React.useCallback((answer) => {
setAnswers((answers) => [...answers, answer]);
setCurrent((current) => current + 1);
}, []); //no dependencies, answers only created on mount
return current < questions.length ? (
<Answer answers={questions[current]} answer={answer} />
) : (
<pre>
answers given:{JSON.stringify(answers, undefined, 2)}
</pre>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>