Why are there so many refs in other people's hooks

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 interview hooks. When he thought of this question, he suddenly realized that react he hookshad 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, useEffectinfinite calls, looking for the reason for a long time, it turned out that we were not very clear about the useEffectconcept 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 reactthe 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 useEffectthe 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

  1. 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.
  2. react Every rendertime it will cause the child component to be re-rendered, the use memocan 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 time  useCallback.

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, reactwe 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 useCallbackmay not be what we imagined, and useCallbackwe have a certain understanding of the correct use

Summarize

So when should you use useCallbackit?

  1. We know that  react when the parent component is updated, the child components will be fully updated. We can cache the  memochild components and make a shallow comparison when updating props. If propsthere is no change, the child components will not be updated. If propsIf there is a function in it, we need to  useCallbackcache the function passed from the parent component to the child component.
  2. useEffectThere may be scenarios that depend on functions in our application . At this time, we need to use useCallbackcached functions to avoid useEffectinfinite 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 useEffectthis hookssupplement react, it is mentioned in the official document that it is recommended that we use custom hooks to encapsulate useEffect .

  1. Then useCallbackthe third scenario used appears, that is, when we customize hooksthe function that needs to be returned, it is recommended to use  useCallbackthe cache, because we don't know what the user is doing with the function we return, in case he adds it to his useEffectdependency Isn't there a problem inside?

a custom hookcase

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

xiaoguo.gif

app.jsxmiddle

image-20230827172546343.png

 MessageBtn.jsxmiddle

image-20230827172851670.png

 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, useCountdownmainly accepting a countdown duration, returning the status of the current time, and a function to start the countdown

image-20230827190803508.png

The function here startis 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 useCountdownto 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  countdownCallBackthe function andonEnd

image-20230827191848587.png

transform useCountdown

  1. Then we define 0 here countis 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
  2. Use  the change of useEffectmonitoring count, and trigger the corresponding method when it changes

The implementation is as follows, the content of the red box is added

image-20230827192510462.png

Ask a question

So, now there is a very serious problem, onEndand  countdownCallBackthese two functions are passed in from the outside, should we put them in our custom hookdependencies useEffect?

We cannot guarantee that the variable passed in must be a wrapped useCallbackfunction, so it must not be placed useEffectin 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

image-20230827193638585.png

  • useMemoizedFn Source code, mainly look at the circled place, the essence is to useRefrecord the incoming content

image-20230827195045906.png

ok, let's use it to  useLatest modify ours useCountdown, the change point is surrounded by a red frame

image-20230827194144821.png

Summarize

In fact, there are two core points of this article

  1. Take everyone to re-learn useCallbackthe usage scenarios. ( useMemosimilar)
  2. 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.

Guess you like

Origin blog.csdn.net/m0_60961651/article/details/132577254