We know that there is a so-called closure trap in the use of
Hooks, consider the following code.
sendMessage to pass the latest value of
text after a click.
However, in reality, the effect of the click is always
sendMessage('') because the callback function is cached by
useCallback, forming a closure.
This is the closure trap.
One solution to the above code is to add a dependency for useCallback.
But after doing so, whenever the dependency (
useCallback will return a new
onClick reference, which defeats the purpose of
useCallback caching function references.
The advent of the closure trap has increased the threshold for getting started with
Hooks and made it easier for developers to write
Now, the official
React team is going to solve this problem.
The solution is to introduce a new native
He is used to define a function that has 2 features.
- it keeps the reference consistent across multiple
renders of the component
- the latest
stateare always available within the function
The above example is modified with
useEvent as follows.
onClick always points to the same reference when the
Chat component is
rendered multiple times.
And the latest value of
text is always available when
onClick is triggered.
useEvent because the
React team believes that the main application scenario for this
Hook is to wrap event handler functions.
The implementation of
useEvent is not difficult, the code is similar to the following.
The whole consists of two parts.
useCallbackwith no dependencies, so that the reference to the function is the same for each
handlerRef.currentat the right time so that the actual function executed is always the latest reference
Differences between ## and open source Hooks
Many open source
Hooks libraries already implement similar functionality (e.g.
The main differences between
useEvent and these open source implementations are that
useEvent is focused on the single scenario of handling event callback functions, while
useMemoizedFn is focused on caching various functions.
So the question is, if the functions are similar, why does
useEvent have to limit itself to a single scenario?
The answer is: for more stability.
useEvent can get the latest
props depends on when
handlerRef.current is updated.
In the above mockup, the logic for
useEvent to update
handlerRef.current is placed in the
This ensures that
handlerRef.current is always updated after the view has finished rendering.
The event callback is apparently triggered after the view has finished rendering, so the latest
props are consistently available.
Note: the actual update timing in the source code is earlier, but that doesn’t affect the conclusion here
fnRef.current is updated when useMemoizedFn is executed (i.e., when the component renders).
React18 has concurrent updates enabled, the number and timing of component
render is uncertain.
So the timing of updates to
useMemoizedFn is also uncertain.
This increases the potential risk when used with concurrent updates.
It can be said that
useEvent limits the application scenario by limiting the update timing of
handlerRef.current, which ultimately leads to stability.
useEvent is still in the RFC (Request For Comments) phase.
Many enthusiastic developers have suggested names for this
Hook, for example:
From these nomenclature, it is clear that they have expanded the application scenario of
As we know from the analysis in this article, expanding the application scenario means increasing the risk of error when developers use it.