Why are there so many refs in other people's hooks
foreword
Recently, due to some reasons
useCallback
, I have some new understandings, and then I met a friend who said that he was asked how to implement a countdown during the interviewhooks
. When he thought of this question, he suddenly realized thatreact
hehooks
had a new idea. Understand, so with this article, record my personal thoughts.
When learning some open source libraries, it is easy to find that hooks
there are many parameters ref
to be stored in the open source library hooks
.
After using it ref
, the place where the variable is used needs .current
to get the value of the variable, which is definitely more troublesome than using the variable directly. For people with code cleanliness, this must be very awkward.
hooks
However, it is frequently used in open source libraries ref
. This is certainly not a point without a reason. So what is the reason that the open source library has to be used .current
to obtain variables?
useCallback
Let’s start with a question, when do we need to use it useCallback
?
Everyone must have an answer in everyone's heart. Let me tell you about my mental journey.
Stage 1 - what is this
When we first started learning react
, we wrote functional components. When we defined functions, we definitely didn’t realize that this function uses useCallback
packages. It's been a while since I wrote the code.
Suddenly one day we encountered a problem, useEffect
infinite calls, looking for the reason for a long time, it turned out that we were not very clear about the useEffect
concept of dependencies, and we stuffed all the variables we used into the dependency array. Coincidentally, our dependencies this time There is a function in the array, and react
the function is recreated every time it is rendered, causing our dependencies to be new every time, and then triggering infinite calls.
Baidu went around, and it turns out that useCallback
it is enough to use this function to cache, so that useEffect
the dependencies in it will not be a new value every time.
Summary: At this stage, we used it for the first time useCallback
and learned that it can cache a function.
Phase 2 - can be cached
There are two points that can be cached
- The cache is right, it will not be recreated every time, will the performance be improved in this way! Then I use the cache for all the functions I use
useCallback
. react
Everyrender
time it will cause the child component to be re-rendered, the usememo
can cache this child component, and then the function passed to the child component also needs to be cached, so I think it is convenient when I define the function in the parent component, and I use the cache all the timeuseCallback
.
Summary: Here we mistakenly think that caching can help us do some performance optimization, but because we don't know the root cause, we can easily abuse it useCallback
Phase 3 - Caching is not necessarily a good thing
At this stage, react
we have been writing for a while, and we learned that caching everywhere is actually better than not caching, because the overhead of caching is not necessarily smaller than the overhead of recreating functions every time.
I must have read a lot of introduction articles here useCallback
, so I recommend the following articles
how-to-use-memo-use-callback , this is all in English, the Nuggets have translated this article, "Good Text Translation" .
Summary: At this point we have roughly realized that using it everywhere useCallback
may not be what we imagined, and useCallback
we have a certain understanding of the correct use
Summarize
So when should you use useCallback
it?
- We know that
react
when the parent component is updated, the child components will be fully updated. We can cache thememo
child components and make a shallow comparison when updatingprops
. Ifprops
there is no change, the child components will not be updated. Ifprops
If there is a function in it, we need touseCallback
cache the function passed from the parent component to the child component. useEffect
There may be scenarios that depend on functions in our application . At this time, we need to useuseCallback
cached functions to avoiduseEffect
infinite calls.
Is it just these two points? That must not be the case, otherwise it would not be related to the title of my article.
In response to useEffect
this hooks
supplement react
, it is mentioned in the official document that it is recommended that we use custom hooks to encapsulate useEffect .
- Then
useCallback
the third scenario used appears, that is, when we customizehooks
the function that needs to be returned, it is recommended to useuseCallback
the cache, because we don't know what the user is doing with the function we return, in case he adds it to hisuseEffect
dependency Isn't there a problem inside?
a custom hook
case
implement a countdown
hooks
Demand introduction
Let's simply implement a countdown function first, and imitate our common function of sending SMS verification codes. page effect
app.jsx
middle
MessageBtn.jsx
middle
The function is relatively simple. When the button is clicked, a timer is created, and then the timer is cleared when the time is up.
Now MessageBtn
write the countdown logic in a custom one hooks
.
useCountdown
Extract some of the logic above, useCountdown
mainly accepting a countdown duration, returning the status of the current time, and a function to start the countdown
The function here start
is used useCallback
, because we can't guarantee that there will be no problems in the user's usage scenario, so let's wrap it
upgrade useCountdown
Now we expect useCountdown
to support two functions, one is called when the countdown is over, and the other is called when the countdown ends
The expected usage is like this, passing a configuration object to countdownCallBack
the function andonEnd
transform useCountdown
- Then we define 0 here
count
is a bit ambiguous, 0 cannot accurately know whether it is 0 at the beginning or 0 at the end of the countdown, so we need to add a flag to indicate that it is currently 0 at the end - Use the change of
useEffect
monitoringcount
, and trigger the corresponding method when it changes
The implementation is as follows, the content of the red box is added
Ask a question
So, now there is a very serious problem, onEnd
and countdownCallBack
these two functions are passed in from the outside, should we put them in our custom hook
dependencies useEffect
?
We cannot guarantee that the variable passed in must be a wrapped useCallback
function, so it must not be placed useEffect
in the dependency.
How to solve this problem?
The answer is to use useRef
. (Going around for so long before asking questions (╥╯^╰╥)
)
Before we use it, we can see what the mature solution is
For example, the implementation of useLatest and useMemoizedFnahooks
inside
useLatest
source code
useMemoizedFn
Source code, mainly look at the circled place, the essence is touseRef
record the incoming content
ok, let's use it to useLatest
modify ours useCountdown
, the change point is surrounded by a red frame
Summarize
In fact, there are two core points of this article
- Take everyone to re-learn
useCallback
the usage scenarios. (useMemo
similar) - When writing customization
hooks
, we need to pay attention to the parameters passed in from the outside, and the return value we return to the user. The core point is to never trust the content passed in from the outside, and absolutely give the user a reliable return value.