In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-12 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces the implementation and origin of ReactHooks and how to solve the problem, the content is very detailed, interested friends can refer to, hope to be helpful to you.
What is the difference between React functional components and React class components?
The general answer is:
Class components have more features than functional components, such as state, but what if there is Hooks? Function components perform better than class components, but in modern browsers, the original performance of closures and classes is significantly different only in extreme scenarios.
Performance depends largely on the role of the code, rather than choosing a functional or class component. Although there are differences in optimization strategies, the performance differences are negligible.
The following focuses on the fundamental difference between functional components and class components of React: in the mental model.
A simple case
Functional components have existed since then, but are often ignored: functional components capture the values used for rendering. (Function components capture the rendered values.)
Think about this component:
Function ProfilePage (props) {const showMessage = () = > alert ('Hello' + props.user); const handleClick = () = > setTimeout (showMessage, 3000); return Follow}
The above components: if props.user is Dan, it will show Hello Dan in three seconds.
How do we write if it is a class component? A simple refactoring might look like this:
Class ProfilePage extends React.Component {showMessage = () = > alert ('Followed' + this.props.user); handleClick = () = > setTimeout (this.showMessage, 3000); render () {return Follow;}}
Usually we think that these two code snippets are equivalent. People are often free to ReFactor code in these two modes, but rarely notice what they mean:
We illustrate the difference through a common error in the React application.
We add a parent component and use a drop-down box to change the props.user passed to the child component (ProfilePage). Instance address: (https://codesandbox.io/s/pjqnl16lm7)
Follow the steps below:
Click one of the Follow buttons. Switch the selected account in 3 seconds. View the pop-up text.
At this point, you get a strange result:
When using functional components to implement ProfilePage, click the Follow button when the current account is Dan, and then immediately switch the current account to Sophie, the pop-up text will still be 'Followed Dan'. When using the ProfilePage implemented by the class component, the pop-up text will be 'Followed Sophie':
In this example, the function component is correct. If I follow one person and then navigate to another person's account, my components should not confuse who I follow. And the implementation of the class component is obviously wrong
Case analysis
So why do class components behave like this in our example? Let's take a closer look at the showMessage method in the class component:
ShowMessage = () = > {alert ('Followed' + this.props.user);}
This class method reads data from the this.props.user.
Props is immutable in React, so they will never change.
And this is and will always be mutable. **
This is also the purpose of the class component this: to get the latest instances in the rendering method and the lifecycle method.
So if our component is re-rendered after the request has been made, the this.props will change. The showMessage method gets the user from a "too new" props.
In this behavior of reading data from this, calling a callback function to read this.props 's timeout causes the showMessage callback not to be "bound" to any particular rendering, so it "loses" the correct props.
How to use class components to solve the above BUG? (assuming that the functional component does not exist)
We want to somehow "fix" the connection between the rendering with the correct props and the showMessage callback that reads these props. Props was lost somewhere.
Method 1: read the this.props before calling the event, and then explicitly pass it to the timeout callback function:
Class ProfilePage extends React.Component {showMessage = (user) = > alert ('Followed' + user); handleClick = () = > {const {user} = this.props; setTimeout (() = > this.showMessage (user), 3000);}; render () {return Followbutton >;}}
However, this approach makes the code significantly more verbose. What if we need more than a props? What if we still need to access state? If showMessage calls another method, and then this.props.something or this.state.something is read in that method, we will have the same problem. Then we have to pass this.props and this.state all the way through each method called by showMessage as function arguments.
This undermines the engineering provided by the class. It's also hard to remember passed variables or enforce them, which is why people are always dealing with bugs.
This problem can be reproduced in any UI library that puts data in mutable objects such as this (not only in React)
Method 2: if we can use JavaScript closure, the problem will be easily solved. *
If you capture the props or state used for that rendering in a particular rendering, you will find that they will always be consistent, as you would expect:
Class ProfilePage extends React.Component {render () {const props = this.props; const showMessage = () = > {alert ('Followed' + props.user);}; const handleClick = () = > {setTimeout (showMessage, 3000);}; return Follow;}}
You have already "captured" props: when you render. In this way, any code inside it, including showMessage, is guaranteed to get the props used for this particular rendering.
The Origin of Hooks
But: if you define various functions in render methods instead of using class methods, what's the point of using classes?
In fact, we can simplify the code by removing the "package" of the class:
Function ProfilePage (props) {const showMessage = () = > {alert ('Followed' + props.user);}; const handleClick = () = > {setTimeout (showMessage, 3000);}; return (Follow);}
As above, props is still captured-- React passes them as parameters. Unlike this, the props object itself is never changed by React.
When the parent component uses a different props to render the ProfilePage, the React calls the ProfilePage function again. But the event handler we clicked "belongs" to the last rendering with its own user value, and the showMessage callback function can also read this value. They're all intact.
That's why, in the functional version above, click follow account 1, and then change the selection to account 2, and you will still pop up 'Followed account 1':
The functional component captures the value used in the rendering.
With Hooks, the same principle applies to state. Look at this example:
Function MessageThread () {const [message, setMessage] = useState (''); const showMessage = () = > {alert ('You said:' + message);}; const handleSendClick = () = > {setTimeout (showMessage, 3000);}; const handleMessageChange = (e) = > {setMessage (e.target.value);}; return Send;}
If I send a specific message, the component should not be confused about which message is actually sent. The message variable of this function component captures the rendering that "belongs" to the click handler that is called by the browser. So when I click "send", message is set to what I typed in input at that moment.
Read the latest status
So we know that functions in React capture props and state by default. But what if we want to read the latest props and state that are not part of this particular rendering? What if we want to "read them from the future"?
In the class, you do this by reading this.props or this.state, because the this itself is variable. React changed it. In functional components, you can also have a variable that is shared in all components rendered frames. It is called "ref":
Function MyComponent () {const ref = useRef (null);}
But you have to manage it yourself.
An ref plays the same role as an instance field. This is the back door to a world of variable commands. You may be familiar with 'DOM refs', but ref is conceptually more general. It's just a box in which you can put things in.
Even visually, this.something is like a mirror of something.current. They represent the same concept.
By default, React does not create refs for the latest props and state in functional components. In many cases, you don't need them, and it would be a waste to distribute them. However, if you like, you can track these values manually like this:
Function MessageThread () {const [message, setMessage] = useState (''); const latestMessage = useRef (''); const showMessage = () = > {alert ('You said:' + latestMessage.current);}; const handleSendClick = () = > {setTimeout (showMessage, 3000);}; const handleMessageChange = (e) = > {setMessage (e.target.value); latestMessage.current = e.target.value;}
If we read the message in showMessage, we will get the message the moment we press the send button. But when we read the latestMessage.current, we will get the latest value-even if we continue typing after pressing the send button.
Ref is a "opt-out" method of rendering consistency, which can be convenient in some cases.
In general, you should avoid reading or setting refs during rendering because they are variable. We want to keep the rendering predictable. However, if we want the latest values for a particular props or state, it can be annoying to update the ref manually. We can automate this by using an effect:
Function MessageThread () {const [message, setMessage] = useState (''); const latestMessage = useRef (''); useEffect () = > {latestMessage.current = message;}); const showMessage = () = > {alert ('You said:' + latestMessage.current);}
We perform an assignment within an effect so that the value of the ref changes only after the DOM is updated. This ensures that our variable mutations do not break features such as time slices and Suspense that depend on interruptible rendering.
Generally speaking, it is not necessary to use such a ref. Capturing props and state is usually a better default. However, ref is handy when dealing with imperative API such as intervals and subscriptions. You can track any value like this-a prop, a state variable, an entire props object, or even a function.
This pattern is also convenient for optimization-- for example, when the useCallback itself changes frequently. However, using a reducer is usually a better solution
Closures help us solve subtle problems that are difficult to notice. Similarly, they make it easier to write code that works correctly in concurrent mode. This is possible because the logic inside the component captures and contains the correct props and state when rendering it.
Functions capture their props and state-- so their identity is just as important. This is not a bug, but a functional component feature. For example, for useEffect or useCallback, functions should not be excluded from "dependency arrays". (the correct solution is usually to use the useReducer or useRef mentioned above.)
When we use functions to write most of our React code, we need to adjust our perception and intuition about optimizing the code and what variables change over time.
The best mental rule I've found about hooks so far is to "write code with the belief that any value can be changed at any time." The React function always captures their values-- now we know why.
About the implementation and origin of ReactHooks and how to solve the problem to share here, I hope that the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.
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.