In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)05/31 Report--
Today, I would like to share with you the relevant knowledge of the principle analysis of React Hooks. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge, so share this article for your reference. I hope you can get something after reading this article. Let's take a look at it.
UseEffect in 0x00 React
There are a lot of Hooks in React, among which useEffect is used very frequently. The benefits of using Hook are: enhancing reusability and making function components stateful.
Data acquisition, subscription, or manual modification of DOM are all side effects (side effects).
Effect is executed after each render of React. If there is some side effect code that needs to be synchronized, you can wrap it with useLayoutEffect, which is similar to useEffect.
UseEffect has two parameters, the first passing a function, and the second parameter as the criterion for whether the effect executes the function in the first parameter, in other words, whether the variable in the second parameter array changes to determine whether the function executes, and whether the function executes depends on whether the value of the second parameter changes. The comparison in React is a shallow equal (shallow comparison). For deep object nesting, it is impossible to accurately judge whether it has changed or not.
UseEffect uses the closure mechanism of JS. It can be said that the first parameter is a closure function, which is in the scope of the function component, and can access local variables and functions at the same time.
Multiple useEffect in series are mounted to the execution chain in turn according to whether the function is executed (depending on whether the value of the item changes).
In class components, there is the concept of life cycle. In some articles on react hooks, you will often see examples of how to simulate componentDidmount and componentUnmount with useEffect, whose second parameter is an empty array [], so that effect executes once when the component is mounted and executes the function of return when it is unloaded. It is also a closure relationship, through a function of return to implement the closure and execute the function of the return before the next time React runs effect, to remove side effects.
Constructing the mental model of React Hooks by 0x01
When individuals first came into contact with react hooks, they felt that the execution of the code was a bit contrary to common sense and spent a lot of time building a reasonable mental model of react. Function components (Functional Component) do not have the concept of life cycle. React controls updates and updates frequently, but some values change and some remain the same, which makes the understandability of the program worse.
However, after continuous learning and use, I personally think that hooks is actually a very lightweight way, in project construction, develop custom hooks, and then call hook anywhere in the application, similar to plug-in (pluggable) development, reducing the coupling of the code. But it also brings some troublesome things, some students write a lot of code in a hook, separate effect is also jumbled together, coupled with multi-dimensional variable control, it is difficult for other students to understand what this hook is doing.
In order to solve the problem of jumbled internal code in hook, we must first clarify the current work of hook, whether it can be split, and whether other hook can be called in hook, so is it possible to split multiple hook? Or organize (sort out) the running logic of the code?
Every rendering in React has its own effect
React hooks update, the author thinks that it can be regarded as a "snapshot", each update is a "snapshot", the value of variables in this snapshot is unchanged, each snapshot will produce serial (deducable) differences because of the update of react, and the function in effect is a new function every time.
To put it simply, my mental model of hooks is a plug-in, stateful, ordered tool function.
0x02 useEffect
Each update for useEffect,React determines whether or not to execute the wrapped function based on the dependency in the second parameter of the useEffect.
React will remember that every update of the effect function,effect function we wrote will work on DOM and let the browser draw the screen, and then call effect function.
The whole execution process can be briefly summarized as follows:
1. When the component is clicked, it triggers an update count of 1, notifying React that "count has been updated to 1"
2.React response, asking for UI with count 1 from the component
3. Components:
a. Give the virtual DOM when count is 1
b. When telling react to finish rendering, remember to call the function () in effect () = > {document.title = 'you click' + 1 +' timesystems'}
4.React informs the browser to draw DOM and update UI
5. The browser informs ReactUI that it has updated to the screen
After receiving the message that the screen drawing is complete, 6.React executes the function in effect so that the title of the page becomes "you click 1 times!".
0x03 useRef
If you are already familiar with the above ideas and processes, you also agree with the concept of "snapshot".
Sometimes, we want to get the latest value in effect, rather than through event capture, the official useRef hook,useRef is a "synchronous" variable in the "life cycle" phase, and we can store the value in its current to ensure that its value is up-to-date.
Why the values described above are captured rather than up-to-date can be understood through setState (x = > x + 1). In some setTimeout asynchronous code, we want to get the latest value so that we can synchronize the latest state, so we use ref to help store the latest updated value.
This paradigm-breaking approach gives the program a hint of dirty, but it does solve a lot of problems, and the benefits of doing so can also show which code is fragile and depends on timing.
In class components, the latest value is also obtained each time through this.setState ().
Cleaning of 0x04 effect
The cleanup of effect is more or less involved in the previous description, just for an understanding, but the description is not entirely accurate.
For example, the following example:
UseEffect (() = > {ChatAPI.subscribeToFriendStatus (props.id, handleStatusChange); return () = > {ChatAPI.unsubscribeFromFriendStatus (props.id, handleStatusChange);};})
Suppose the props is {id: 10} the first time and {id: 20} the second time. You might think that the following things happened:
React cleared the effect of {id: 10}.
React renders the UI of {id: 20}.
React runs effect for {id: 20}.
However, this is not the case, and if you follow this mental model, the value obtained at cleanup is the previous value, because the cleanup is done before rendering the new UI. This contradicts the earlier statement that React only executes effects after the browser has drawn it.
The advantage of React is that it does not block a rendering (screen update) of the browser. Of course, according to this rule, the removal of effect is also delayed until the browser draws the UI. Then the correct order of execution should be:
React rendered the UI of id 20
React cleared effect from id 10
React runs effect of id 20
So why is it that what is cleared in effect is old?
Each function within the component (including event handlers, effects, timer, or API calls, etc.) captures the props and state in the rendering that defined them.
Then, the purge of effect does not read the "latest" props, it can only read the value of props in the rendering that defines it.
Those who are eliminated in the process of human development are always old-fashioned who do not want to make progress. The same is true in React, which may be radical, but most people always look forward to "replacing the old with the new."
Update dependency of 0x05 effect
The second parameter in useEffect can be an array of parameters (dependent arrays). React updates DOM's ideas, showing only the results to the world, regardless of the process.
When React updates a component, it compares props, AST, etc., and then only needs to update the changed DOM.
The second parameter is equivalent to telling useEffect that you can execute effect as long as one of the parameters I give you changes. In this way, you can reduce the number of calls to effect after each render, and reduce the meaningless waste of performance.
In the process of development, we will try to obtain remote data through api when the component is loaded, and apply it to the data rendering of the component, so we use the following simple example:
UseEffect (() = > {featchData ();}, [])
Because it is an empty array, the remote data is obtained only once when the component is mounted (mount), and then it will not be executed again. If a local variable is involved in the effect, it will change according to the current state, and the function will be created each time (a new anonymous function created each time).
Function Counter () {const [count, setCount] = useState (0); useEffect () = > {const id = setInterval (()) = > {setCount (count + 1);}, 1000); return () = > clearInterval (id);}, []); return {count};}
You might think that the above example will be count+1 on UI per second after the component is loaded, but the reality is that it will only be executed once. And why is that? Do you think it's a little counterintuitive?
Because count,effect is not added to the dependency of effect, only an anonymous function is created the first time it is rendered. Although count + 1 is executed every second through the setInterval package, the value of count is always 0, so the UI representation always renders 1.
Of course, through some rules, we can change its value by adding count, or through useRef, or through setState (x = > x = 1), the pattern to get the latest value. For example, the following cool techs operation:
/ / useRef function Example () {const [count, setCount] = useState (0); const countRef = useRef (count); countRef.current = count; / / what if this line of code is put into the effect function? Think about it! / / answer: it exists when count is declared by effect anonymous function in effect, and the value is 0. Then the count value obtained is also the count before rendering (the value in this props is 0. Review the concept of snapshot again). However, since there are no dependencies in the dependency array, the anonymous function will not be executed again. / / however, due to setInterval, the function will continue to setCount, and the key is the parameters. The value taken by countRef.current = count; is the value of 0 in the first snapshot, so the updated value is always 0. 1 = 1. Such a result is in line with the expected rules. / / then why just leave it outside? Because countRef.current synchronizes the latest value of count, gets a new count value before each render, and assigns it to countRef.current. Because of the synchronization characteristics of ref (timeliness and unity), the countRef.current obtained in the loop is also the latest value, so it can achieve the counting effect useEffect (() = > {const id = setInterval (()) = > {setCount (countRef.current + 1);}, 1000); return () = > clearInterval (id) }, []); return {count};} / setState pass in the function function Example () {const [count, setCount] = useState (0); useEffect () = > {const id = setInterval (()) = > {setCount (x = > x + 1); / / when the passing parameter is a function, the first parameter passed by default is the previous value, which is the hook of useState in processing}, 1000) Return () = > clearInterval (id);}, []); return {count};} / / use useReducer function Counter ({step}) {const [count, dispatch] = useReducer (reducer, 0); function reducer (state, action) {if (action.type = 'tick') {return state + step;} else {throw new Error () }} useEffect (() = > {const id = setInterval (() = > {dispatch ({type: 'tick'});}, 1000); return () = > clearInterval (id);}, [dispatch]); return {count};}
The above approach is actually a bit self-deceiving. You can see the log in the figure below. The value of the count variable in the setInterval anonymous function has not changed, which may bring some risks to our business.
Demo example
However, in general, if you do not have a full understanding of the business or procedures, I do not recommend that you do so.
For dependencies, first, you have to honestly write the associated parameters, and secondly, you can optimize the effect to consider whether a parameter is really needed and can be replaced?
The values wrapped by dispatch, setState, and useRef in the dependency are all unchanged, and these parameters can be removed from the dependency.
Dependencies are functions
You can define the function into useEffect so that the added dependency becomes a parameter to the function, so that useEffect does not need to add the xxx function name as a dependency.
In addition, if you simply put the function name in the dependency, and if the function is reused in multiple effects, then every time render, the function is redeclared (the new function), then the effects will be executed frequently because of the new function, which is the same as not adding a dependent array, and does not have any optimization effect, so how to improve it?
Method 1:
If the function does not use any value within the component, then the function is defined outside the component. The function is not in the rendering scope and is not affected by the data flow, so it will never change.
Method 2:
Using useCallback hook to wrap a function, similar to useEffect, its second parameter is also a dependency on whether the function is updated or not
0x06 race
It is common in the problem of asynchronous request data, first-come-first-come, first-come-first-come. This is called race. If the asynchronous function supports cancellation, you can cancel it directly.
Then it is easier to cancel the asynchronous request by adding a tag value of type boolean to the async.
Function Article ({id}) {const [article, setArticle] = useState (null); useEffect () = > {let didCancel = false; async function fetchData () {const article = await API.fetchArticle (id); if (! didCancel) {setArticle (article);}} fetchData (); return () = > {didCancel = true;};}, [id]) / /...}
According to the previous rule, such as id=19, and the time to obtain data is 30s, which becomes id=20, and the time to obtain data is only 5s, then the execution order should be as follows:
Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community
Id=19 component uninstalls, didCancle=true, when id=19 asynchronous request receives data 30s later, because! didCancle= false, data update is not performed
Id=20, due to the change of id, first set didCancle=false to request to get the data, then get the data after 5s, then update the data, and finally render the updated data to the screen
These are all the contents of the article "Analysis of the principles of React Hooks". Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.