简体   繁体   English

React:事件回调中的道具值未更新

[英]React: Prop value inside event callback not updated

I have a fairly simple case, I didn't think it would cause me problems.我有一个相当简单的案例,我认为这不会给我带来问题。 If Shift key is pressed I want to add a e.preventDefault() to my selectstart DOM event using React.如果按下 Shift 键,我想使用 React 将e.preventDefault()添加到我selectstart DOM 事件中。 Inoticed that the problem is that the isShiftDown doesn't update correctly.注意到问题是isShiftDown没有正确更新。 I don't understand why this is happening.我不明白为什么会这样。

The isShiftDown isnside handleSelectStart function in Paragraph component is always false . Paragraph组件中的isShiftDown isside handleSelectStart function 始终为false The same value inside App component toggle correctly. App组件内的相同值可以正确切换。

All I have to do is prevent text selecting inside Paragraph if Shift is pressed.如果按下 Shift,我所要做的就是防止在段落内选择文本。 StackBlitz example may seem strange, but my real case much more expanded. StackBlitz 示例可能看起来很奇怪,但我的真实案例要扩展得多。

stackblitz example 堆栈闪电战示例

 // Paragraph const Paragraph = ({ isShiftDown }) => { let paragraphRef; const handleSelectStart = e => { console.log('Paragraph => handleSelectStart => isShiftDown =', isShiftDown); if (isShiftDown) { e.preventDefault(); } }; React.useEffect(() => { paragraphRef.addEventListener('selectstart', handleSelectStart, false); return () => { paragraphRef.removeEventListener('selectstart', handleSelectStart); }; }, []); return ( <p ref={e => (paragraphRef = e)}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p> ); }; // App const App = () => { const [isShiftDown, setIsShiftDown] = React.useState(false); const handleKeyUp = e => { if (e.key === 'Shift' && isShiftDown) { setIsShiftDown(false); } }; const handleKeyDown = e => { if (e.key === 'Shift' &&;isShiftDown) { setIsShiftDown(true); } }. React.useEffect(() => { document,addEventListener('keyup', handleKeyUp; false). document,addEventListener('keydown', handleKeyDown; false). return () => { document,removeEventListener('keyup', handleKeyUp; false). document,removeEventListener('keydown', handleKeyDown; false); }, }; []); return ( <div className="App"> <Paragraph isShiftDown={isShiftDown} /> </div> ); }. ReactDOM,render( <App />. document;getElementById("react") );
 <div id="react"></div> <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>

First, your unbinding cannot work, due to the fact that every time the component is re-evaluated, the event handlers' variables point to a new function. You should save a reference to it inside useEffect or simply use useCallback when defining the handlers:首先,您的解除绑定无法工作,因为每次重新评估组件时,事件处理程序的变量都会指向一个新的 function。您应该在useEffect中保存对它的引用,或者在定义处理程序时简单地使用useCallback

const handleKeyUp = useCallback(e => {
    if (e.key === "Shift" && setIsShiftDown) {
      setIsShiftDown(false);
    }
}, [setIsShiftDown])

Also, keyboard events should be binded at the window level object and not the document .此外,键盘事件应绑定在window级别 object 而不是document

You should write it as follows:你应该这样写:

import React, { useEffect, useCallback } from "react";

export default function Paragraph({ isShiftDown }) {
  let paragraphRef;

  const handleSelectStart = useCallback( <---------- WRAP WITH HOOK
    e => {
      console.log("Paragraph => handleSelectStart => isShiftDown =", isShiftDown)
      if (isShiftDown) {
        e.preventDefault()
      }
    }, [isShiftDown])

  useEffect(() => {
    const ref = paragraphRef;

    ref.addEventListener("selectstart", handleSelectStart);
    return () => {
      ref.removeEventListener("selectstart", handleSelectStart);
    };
  }, [isShiftDown]) // <---------- ADD DEPENDENCY

  return (
    <p ref={el => (paragraphRef = el)}>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </p>
  )
}

Explenation:解释:

Every time Paragraph component gets called from App.js , it basically calls the Paragraph function, which has its own scope, its own paragraphRef and so on.每次App.js调用Paragraph组件时,它基本上都会调用Paragraph function,它有自己的 scope、自己的paragraphRef等等。 React can be very confusing if fundamentals are not well understood.如果基础知识没有得到很好的理解,React 可能会非常混乱。

Knowing the above, you will know if a piece of code inside the component is running in the scope of the latest iteration of the component, or a previous one.知道了以上,你就知道组件内部的一段代码是运行在组件最新迭代的scope,还是之前的那个。
How to know?怎么知道? Reading the code carefully and step-by-step simulating the flow in your mind, creating a vision of how it will act on the next time it is called.仔细阅读代码并逐步模拟您脑海中的流程,创建下一次调用时它将如何执行的愿景。 Knowing JS fundementals and knowing React is key to proper brain-parser which case save a lot of debugging time.了解JS基础知识和了解React是正确的大脑解析器的关键,这可以节省大量调试时间。 it's all about the brain-parser.这都是关于大脑解析器的。

Since you did not specify any dependencies for the useEffect in Paragraph.js`, it will only run once , on the first instance, and that's it.由于您没有useEffect in指定任何依赖项,因此它只会在第一个实例上运行一次,仅此而已。

You must re-bind the events every time the component re-renders, so everything will work with the last "version" of the DOM, as you intend, and not previous renders:每次组件重新渲染时,您都必须重新绑定事件,因此一切都将按照您的意图使用 DOM 的最后一个“版本”,而不是以前的渲染:

useEffect(() => {
  ...
}, [isShiftDown]);

You don't really need to wrap the event callback with useCallback , but I would prefer to, in this scenario.你真的不需要用useCallback包装事件回调,但在这种情况下我更愿意这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 React 钩子值正确呈现但未在 addEventListener 的回调 function 中更新 - React hooks value renders correctly but not updated inside a callback function of addEventListener eventInfo.currentTarget.value 在 React 回调中崩溃,但在事件处理程序中没有? - eventInfo.currentTarget.value crashes inside React callback but not in event handler? React-App:道具在下一个事件之后更新 - React-App: Prop is updated after the next event 事件处理程序中的反应道具嵌套值不正确 - React prop nested value is incorrect in event handler 在 react 中跟踪 children prop 的值或事件变化 - Track the value or event change of children prop in react React useState 值未在 ref 回调中更新 - React useState value not updated in ref callback 为什么在回调函数中反应状态(数组)为空? 为什么不使用来自外部范围的更新值? - Why is react state(array) empty inside callback function? Why is it not using the updated value from outer scope? 在反应中访问回调中的 event.target - Accessing event.target inside callback in react 更新的状态值未反映在 React 的 setInterval() 中 - Updated state value is not reflected inside setInterval() in React 在 React 组件状态/道具中的第一个 onComplete 事件之后更改值 - Change value after first onComplete event in React Component state / prop
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM