各种键盘快捷键的挂钩

时间:2020-07-16 11:40:08

标签: javascript reactjs react-hooks

我有一个具有多种选择的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个快捷键,但是我希望不要对键盘快捷键的数量进行硬编码。

2 个答案:

答案 0 :(得分:3)

由于Rules of Hooks,您无法动态调用钩子,更好的方法是使用composition

您的Choice组件应该有一个hotKeycallback道具,父母应该决定选择的数量。

const Choice = ({ hotKey, callback }) => {
  useHotKey(hotKey, callback);
  return <>...</>;
};

// Usages
<Choice hotKey="1" callback={()=>console.log('1')} />
choices.map((_,index) => <Choice key={index} hotKey={index} ... />);

请参见Thinking in ReactHMR's code example

答案 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>

相关问题