如何使用useEffect挂钩注册事件? [英] How to register event with useEffect hooks?

查看:81
本文介绍了如何使用useEffect挂钩注册事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习有关如何使用钩子注册事件的Udemy课程,讲师给出了以下代码:

I am following a Udemy course on how to register events with hooks, the instructor gave the below code:

  const [userText, setUserText] = useState('');

  const handleUserKeyPress = event => {
    const { key, keyCode } = event;

    if (keyCode === 32 || (keyCode >= 65 && keyCode <= 90)) {
      setUserText(`${userText}${key}`);
    }
  };

  useEffect(() => {
    window.addEventListener('keydown', handleUserKeyPress);

    return () => {
      window.removeEventListener('keydown', handleUserKeyPress);
    };
  });

  return (
    <div>
      <h1>Feel free to type!</h1>
      <blockquote>{userText}</blockquote>
    </div>
  );

现在效果很好,但我不相信这是正确的方法.原因是,如果我理解正确,那么每次重新渲染时,事件都会每次都在注册和注销,而我根本不认为这样做是正确的方法.

Now it works great but I'm not convinced that this is the right way. The reason is, if I understand correctly, on each and every re-render, events will keep registering and deregistering every time and I simply don't think it is the right way to go about it.

所以我对下面的useEffect钩子做了一些修改

So I made a slight modification to the useEffect hooks to below

useEffect(() => {
  window.addEventListener('keydown', handleUserKeyPress);

  return () => {
    window.removeEventListener('keydown', handleUserKeyPress);
  };
}, []);

通过使用空数组作为第二个参数,从而使组件仅运行效果一次,从而模仿componentDidMount.当我尝试结果时,奇怪的是,在我键入的每个键上都没有附加,而是被覆盖了.

By having an empty array as the second argument, letting the component to only run the effect once, imitating componentDidMount. And when I try out the result, it's weird that on every key I type, instead of appending, it's overwritten instead.

我期望 setUserText(${userText}${key}); 将新类型的键附加到当前状态并设置为新状态,但是,它忘记了旧状态并用新状态重写.

I was expecting setUserText(${userText}${key}); to have new typed key append to current state and set as a new state but instead, it's forgetting the old state and rewriting with the new state.

在每次重新渲染时我们都应该注册和注销事件真的是正确的方法吗?

Was it really the correct way that we should register and deregister event on every re-render?

推荐答案

解决此类情况的最佳方法是查看事件处理程序中的操作.如果仅使用先前的状态来设置状态,则最好使用回调模式并仅在初始安装时注册事件侦听器.如果您不使用callback pattern( https://reactjs.org/docs/hooks -reference.html#usecallback )事件侦听器正在使用侦听器引用及其词法范围,但是会创建一个新函数,并在新渲染器上更新了闭包,因此在处理程序中,您将无法更新状态

The best way to go about such scenarios is to see what you are doing in the event handler. If you are simply setting state using previous state, its best to use the callback pattern and register the event listeners only on initial mount. If you do not use the callback pattern (https://reactjs.org/docs/hooks-reference.html#usecallback) the listeners reference along with its lexical scope is being used by the event listener but a new function is created with updated closure on new render and hence in the handler you will not be able to the updated state

const [userText, setUserText] = useState('');

  const handleUserKeyPress = useCallback(event => {
    const { key, keyCode } = event;

    if (keyCode === 32 || (keyCode >= 65 && keyCode <= 90)) {
      setUserText(prevUserText => `${prevUserText}${key}`);
    }
  }, []);

  useEffect(() => {
    window.addEventListener('keydown', handleUserKeyPress);

    return () => {
      window.removeEventListener('keydown', handleUserKeyPress);
    };
  }, [handleUserKeyPress]);

  return (
    <div>
      <h1>Feel free to type!</h1>
      <blockquote>{userText}</blockquote>
    </div>
  );

这篇关于如何使用useEffect挂钩注册事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆