简体   繁体   中英

React.useMemo() and Event Listener

I'm building a REACT App using Hooks, and now I'm facing an issue when using useMemo() and some event listener. i've, prepared a simpler demo of my problem on CodeSandBox: here's the link → https://codesandbox.io/s/mystifying-hertz-21jov?fontsize=14&hidenavigation=1&theme=dark .

Now, let me explain where's the problem: I have buttonData which is computed using useMemo() . Now, let's took a look into the console output: 在此处输入图片说明

At first, buttonData is computed on first render, and buttonData.behavior is equal to test1 . Then, when I enter the button, inside onMouseEnterButton I use setTargetDOM : this will trigger buttonData to be recomputed, since setTargetDOM is one of its dependencies.
So far, so good:

  1. In the console first line, we see that buttonData.behavior is test1 ;
  2. In the second line we see that we enter onMouseEnterButton , and that right now buttonData.behavior is test1 ;
  3. In third line we see that, since targetDOM has changed, we have computed again buttonData , and now buttonData.beavhior is equal to test2 ;

And now, here comes the problem, what I don't understand! I can somehow accept the fact that the fourth console line tells me that buttonDat.behavior is still test1 , since we are still in the same function that changed targetDOM and thus triggered buttonData to change (even if I expected to see buttonData.behavior: test2 even in the fourth line.

What's even worste is that, inside onMouseMoveButton I see buttonData.behavior equals to test1 , and not test2 ..

The question is simple.. Why? I mean, I thought implementing this way I had test2 , but I guess I'm missing some React Hook stuff right here.

onMouseMoveButton and onMouseEnterButton capture buttonData.behavior on the first render and because you never update the event listeners they will always refer to the initial value of buttonData.behavior

What you can do is add buttonData.behavior to the dependencies array of useLayoutEffect and every time buttonData.behavior changes it will run the returned function and remove the previous listeners and add new ones

React.useLayoutEffect(() => {
  ...
}, [buttonData.behavior])

Also, state updates are asynchronous so you in line 4 you can't really log the updated state after you set it

setTargetDOM(e.currentTarget);
// this will never the updated value because 
// the state updater hasn't run yet
console.log(buttonData.behavior);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM