首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >React不更新状态(React-Hooks)

React不更新状态(React-Hooks)
EN

Stack Overflow用户
提问于 2021-02-23 17:15:50
回答 1查看 63关注 0票数 0

我有以下设置:

代码语言:javascript
复制
  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的方法:

代码语言:javascript
复制
  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

我遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-23 20:06:05

问题出在useKeypress钩子中的useEffect

代码语言:javascript
复制
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的依赖项数组中

代码语言:javascript
复制
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,以便对该函数进行记忆:

代码语言:javascript
复制
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]
); 
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66330235

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档