我有以下设置:
const templates = [
'dot',
'line',
'circle',
'square',
];
const [currentTemplate, setCurrentTemplate] = useState(0);
const changeTemplate = (forward = true) => {
let index = currentTemplate;
index = forward ? index + 1 : index - 1;
if (index > templates.length - 1) {
index = 0;
} else if (index < 0) {
index = templates.length - 1;
}
setCurrentTemplate(index);
};
useEffect(() => {
console.log(`Current Template is: ${templates[currentTemplate]}`);
}, [currentTemplate]);
useKeypress('ArrowLeft', () => {
changeTemplate(false);
});
useKeypress('ArrowRight', () => {
changeTemplate(true);
});这是使用useKeypress Hook的方法:
import { useEffect } from 'react';
/**
* useKeyPress
* @param {string} key - the name of the key to respond to, compared against event.key
* @param {function} action - the action to perform on key press
*/
export default function useKeypress(key: string, action: () => void) {
useEffect(() => {
function onKeyup(e: KeyboardEvent) {
if (e.key === key) action();
}
window.addEventListener('keyup', onKeyup);
return () => window.removeEventListener('keyup', onKeyup);
}, []);
}每当我按下向左或向右箭头键时,该函数都会被触发。但是currentTemplate变量并没有改变。它始终保持为0。只有当我从左到右或以其他方式切换按键时,useEffect才会触发。单击同一个键两次,不会再次触发useEffect,但它应该触发!当从右向左更改时,输出为Current Template is: square;当从左向右更改时,输出为Current Template is: line。但这一点永远不会改变。currentTemplate的值始终保持为0。
我遗漏了什么?
发布于 2021-02-23 20:06:05
问题出在useKeypress钩子中的useEffect。
export default function useKeypress(key: string, action: () => void) {
useEffect(() => {
function onKeyup(e: KeyboardEvent) {
if (e.key === key) action();
}
window.addEventListener('keyup', onKeyup);
return () => window.removeEventListener('keyup', onKeyup);
}, []); // ? problem
}钩子是一个没有依赖项的单一useEffect。也就是说,它只会发射一次。这是你传递给这个钩子的action的一个问题。只要组件中的changeTemplate-action发生更改(即在重现器上),对此的引用就不会在useKeypress-hook中更新。
要解决此问题,需要将action添加到useEffect的依赖项数组中
export default function useKeypress(key: string, action: () => void) {
useEffect(() => {
function onKeyup(e: KeyboardEvent) {
if (e.key === key) action();
}
window.addEventListener('keyup', onKeyup);
return () => window.removeEventListener('keyup', onKeyup);
}, [action]); // ? whenever `action` changes, the effect will be updated
}这是为了确保每当给定的action发生变化时,效果都会更新。在此更改之后,事情应该会像预期的那样工作。
优化:
此时,将为每个渲染重新生成useEffect,因为将为每个渲染实例化changeTemplate函数。为了避免这种情况,您可以用useCallback包装changeTemplate,以便对该函数进行记忆:
const changeTemplate = useCallback(
(forward = true) => {
let index = currentTemplate;
index = forward ? index + 1 : index - 1;
if (index > templates.length - 1) {
index = 0;
} else if (index < 0) {
index = templates.length - 1;
}
setCurrentTemplate(index);
},
// Regenerate the callback whenever `currentTemplate` or `setCurrentTemplate` changes
[currentTemplate, setCurrentTemplate]
); https://stackoverflow.com/questions/66330235
复制相似问题