Javascript 如何使用useEffect挂钩注册事件?

Javascript 如何使用useEffect挂钩注册事件?,javascript,reactjs,react-native,react-hooks,Javascript,Reactjs,React Native,React Hooks,我正在学习如何使用挂钩注册事件的课程,讲师给出了以下代码: const[userText,setUserText]=useState(“”); const handleUserKeyPress=事件=>{ const{key,keyCode}=事件; 如果(keyCode==32 | |(keyCode>=65&&keyCode{ window.addEventListener('keydown',handleUserKeyPress); return()=>{ window.removeEve

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

const[userText,setUserText]=useState(“”);
const handleUserKeyPress=事件=>{
const{key,keyCode}=事件;
如果(keyCode==32 | |(keyCode>=65&&keyCode{
window.addEventListener('keydown',handleUserKeyPress);
return()=>{
window.removeEventListener('keydown',handleUserKeyPress);
};
});
返回(
自由打字!
{userText}
);
现在它工作得很好,但我不相信这是正确的方式。原因是,如果我理解正确,在每次重新渲染时,事件都会不断注册和注销,我认为这不是正确的方式

所以我对下面的
useffect
钩子做了一点修改

useffect(()=>{
window.addEventListener('keydown',handleUserKeyPress);
return()=>{
window.removeEventListener('keydown',handleUserKeyPress);
};
}, []);
通过使用空数组作为第二个参数,让组件只运行一次效果,模仿
componentDidMount
。当我尝试结果时,奇怪的是,在我键入的每个键上,它不是附加,而是被覆盖

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


在第二种方法中,
useffect
只绑定一次,因此,
userText
永远不会更新。一种方法是在ev上维护一个随
userText
对象一起更新的局部变量埃利按键

  const [userText, setUserText] = useState('');
  let local_text = userText
  const handleUserKeyPress = event => {
    const { key, keyCode } = event;

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

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

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

  return (
    <div>
      <h1>Feel free to type!</h1>
      <blockquote>{userText}</blockquote>
    </div>
  );
const[userText,setUserText]=useState(“”);
让本地_text=userText
const handleUserKeyPress=事件=>{
const{key,keyCode}=事件;
如果(keyCode==32 | |(keyCode>=65&&keyCode{
window.addEventListener('keydown',handleUserKeyPress);
return()=>{
window.removeEventListener('keydown',handleUserKeyPress);
};
}, []);
返回(
自由打字!
{userText}
);
就我个人而言,我不喜欢这个解决方案,觉得
反反应
,我认为第一种方法已经足够好了,而且是专门为这种方式设计的。

新答案:

useEffect(() => {
  function handlekeydownEvent(event) {
    const { key, keyCode } = event;
    if (keyCode === 32 || (keyCode >= 65 && keyCode <= 90)) {
      setUserText(prevUserText => `${prevUserText}${key}`);
    }
  }

  document.addEventListener('keyup', handlekeydownEvent)
  return () => {
    document.removeEventListener('keyup', handlekeydownEvent)
  }
}, [])
因为在
useffect()
方法中,它取决于
userText
变量,但您不将它放在第二个参数中,否则
userText
将始终绑定到带有参数
[]
的初始值
'


您不需要这样做,只想让您知道第二个解决方案不起作用的原因。

您需要一种方法来跟踪以前的状态。
useState
只帮助您跟踪当前状态。从中,可以使用另一个钩子访问旧状态

const prevRef = useRef();
useEffect(() => {
  prevRef.current = userText;
});
我已经更新了你的例子来使用这个。它是有效的

const{useState,useffect,useRef}=React;
常量应用=()=>{
const[userText,setUserText]=useState(“”);
const prevRef=useRef();
useffect(()=>{
prevRef.current=用户文本;
});
const handleUserKeyPress=事件=>{
const{key,keyCode}=事件;
如果(keyCode==32 | |(keyCode>=65&&keyCode{
window.addEventListener(“向下键”,handleUserKeyPress);
return()=>{
window.removeEventListener(“向下键”,handleUserKeyPress);
};
}, []);
返回(
自由打字!
{userText}
);
};
ReactDOM.render(,document.getElementById(“根”);

对于您的用例,
useffect
需要依赖关系数组来跟踪更改,并根据依赖关系确定是否重新呈现。建议始终将依赖关系数组传递给
useffect
。请参阅下面的代码:

我已经介绍了
useCallback
hook

const { useCallback, useState, useEffect } = React;

  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>
      <blockquote>{userText}</blockquote>
    </div>
  );
const{useCallback,useState,useffect}=React;
const[userText,setUserText]=useState(“”);
const handleUserKeyPress=useCallback(事件=>{
const{key,keyCode}=事件;
如果(keyCode==32 | |(keyCode>=65&&keyCode`${prevUserText}${key}`);
}
}, []);
useffect(()=>{
window.addEventListener(“向下键”,handleUserKeyPress);
return()=>{
window.removeEventListener(“向下键”,handleUserKeyPress);
};
},[handleUserKeyPress]);
返回(
{userText}
);

您无权访问已更改的useText状态。您可以将其复制到prevState。将状态存储在变量中,例如:state like so:

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

  useEffect(() => {
    let state = ''

    const handleUserKeyPress = event => {
      const { key, keyCode } = event;
      if (keyCode === 32 || (keyCode >= 65 && keyCode <= 90)) {
        state += `${key}`
        setUserText(state);
      }   
    };  
    window.addEventListener('keydown', handleUserKeyPress);
    return () => {
      window.removeEventListener('keydown', handleUserKeyPress);
    };  
  }, []);

  return (
    <div>
      <h1>Feel free to type!</h1>
      <blockquote>{userText}</blockquote>
    </div>
  );  
};
const-App=()=>{
const[userText,setUserText]=useState(“”);
useffect(()=>{
让状态=“”
const handleUserKeyPress=事件=>{
const{key,keyCode}=事件;
如果(keyCode==32 | |(keyCode>=65&&keyCode{
window.removeEventListener('keydown',handleUserKeyPress);
};  
}, []);
返回(
自由打字!
{userText}
);  
};

处理此类场景的最佳方法是查看您在事件处理程序中执行的操作。如果您只是使用前一个状态设置状态,则最好使用回调模式并仅在初始装载时注册事件侦听器。如果您不使用
回调模式()事件侦听器正在使用侦听器引用及其词法作用域,但在新呈现时会创建一个新函数,并使用更新的闭包,因此在处理程序中,您将无法访问更新的状态

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>
  );
const[userText,setUserText]=useState(“”);
const handleUserKeyPress=useCallback(事件=>{
const{key,keyCode}=事件;
如果(键代码===3
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>
  );
setUserText(prev => `${prev}${key}`);