Functional setState is the future of React — freeCodeCamp.org
React/setState/setState/React/setState/setState As recorded in this article, I googled and saw this article. About setState, this article explains in detail and in depth 👍, so translate it to Nuggets for more people to see.
Update: I have a follow-up discussion on this topic here at React Rally. Although this article is more about the “functional setState” pattern, it is more about understanding setState in depth.
A share I did on React Rally about setState: Justice MBA-Demystifying setState() – YouTube
React promotes functional programming in JavaScript, which has led to a number of frameworks adopting the component-based UI pattern used by React. Today, the functional craze is spreading throughout the Web development ecosystem.
Translator’s Note: The above is translated as follows:
The JavaScript ecosystem is moving from ‘New Framework of the Week’ to ‘New (faster) React Clone of the Week’
Alibaba has released their own React class framework that seems to be lighter and faster – but there’s definitely a downside! github.com/alibaba/rax
But the React team is far from relaxing. They continued to dig deeper, exploring more functional gems.
So today I’m going to reveal a functional gem hidden in React – functional setState!
Well, I just made up the name…… And it’s not entirely new or secret. No, not really. It’s actually a pattern built into React that very few developers know about. It never had a name, but now it can be called – function setState!
As Dan Abramov describes it, the functional setState is one such pattern:
Declare state changes separately from component classes.
Yi?
Okay… Here’s what you already know
React is a component-based UI library. A component is basically a function that takes some properties and returns a UI element.
function User(props) {
return (
<div>A pretty user</div>
);
}
Copy the code
Components may need to own and manage their state. In this case, you typically write components as classes. Your state then resides in the constructor function of the class:
class User {
constructor () {
this.state = {
score : 0
};
}
render () {
return (
<div>This user scored {this.state.score}</div>); }}Copy the code
To manage state, React provides a special method called setState (). Usage:
class User {... increaseScore () {this.setState({score : this.state.score + 1}); }... }Copy the code
Notice how setState () works. You pass an object that contains the state part to be updated. In other words, the object you pass will have a key corresponding to the key in the component state, and then setState () updates or sets the state by merging the object into state. This is the “set – State”
You may not know this
Remember how setState () works? So, what if I told you you could pass a function instead of passing an object?
Yes. SetState () also takes a function as an argument. This function takes the previous state of the component and the current props, which is used to calculate and return the next state. As follows:
this.setState(function (state, props) {
return {
score: state.score - 1}});Copy the code
Note that setState () is a function to which we pass another function (functional programming… Function setState). At first glance, the code might look ugly, with just too many steps to set up the state. But why do we have to do this?
Why pass the function to setState?
The point is, status updates can be asynchronous.
Think about what happens when setState () is called. React will first merge the object passed to setState () into the current state. Then it will start merging. It creates a new React Element tree (the object representation of the UI), differentiates the new tree from the old one, finds out what has changed based on the object passed to setState (), and finally updates the DOM.
Shout! So much work! In fact, this is even a simplified summary. But trust React:
React does not simply “set-state”.
Because of the amount of work involved, calling setState () may not update your status immediately.
React can batch multiple calls to setState () into a single update to improve performance.
What does the above sentence mean?
First, “calling setState () multiple times” might mean calling setState () multiple times within a function, as follows:
state = {score : 0};
// Call setState () several times
increaseScoreBy3 () {
this.setState({score : this.state.score + 1});
this.setState({score : this.state.score + 1});
this.setState({score : this.state.score + 1});
}
Copy the code
Now, when React encounters “multiple calls to setState ()” instead of executing “set-state” three full times, React will avoid much of the work I described above and subtly say to itself, “No! I’m not going to update my status every time. I’d rather get a container that wraps all these slices together and just updates them once. “This is batch processing!
Remember that setState () is passed a normal object. Now, assuming that anytime React encounters “multiple calls to setState (),” it does the batch by extracting all the objects passed to each setState () call, merging them together to form a single object, and then using that single object to execute setState ().
In JavaScript, the merged object might look like this:
const singleObject = Object.assign(
{},
objectFromSetState1,
objectFromSetState2,
objectFromSetState3
);
Copy the code
This pattern is called object composition.
In JavaScript, objects are “merged” or combined: if three objects have the same key, the key value of the last Object passed to Object.assign () will be the final value of that key. Such as:
const me = {name : "Justice"},
you = {name : "Your name"},
we = Object.assign({}, me, you);
we.name === "Your name"; //true
console.log(we); // {name : "Your name"}
Copy the code
Because you is the last object to be merged into we, the name value in the you object – “Your name” – will override the value of name in the ME object.
So if setState () is called multiple times with an object as an argument — passing one object at a time — React will merge. In other words, it will make a new object out of the multiple objects we passed around. If any object contains the same key, the value of the key of the last object with the same key is stored. Isn’t it?
This means that, given our increaseScoreBy3 function above, the end result of the function will just be 1 instead of 3, since React did not immediately update the state in the order in which we called setState (). First, React groups all objects together as follows: {score: this.state.score + 1}, and then “set-state” the newly combined object only once. User.setstate ({score: this.state.score + 1}).
To be very clear, passing objects to setState () is not the problem. The real problem is passing the object to setState () when you want to calculate the next state based on the previous state. So stop doing that. It’s not safe!
Because this.props and this.state can be updated asynchronously, you should not rely on their values to calculate the next state.
Sophia Shoemaker’s example illustrates the problem. Demonstrate it, and note the bad and good solutions in this example.
The function setState solves our problem
If you haven’t taken the time to demonstrate the above example, I highly recommend that you take a look at it first, as it will help you grasp the core concepts of this article.
When you demonstrate the above example, you can no doubt see that the function setState solves our problem. But how does it work?
Let’s talk to the core members of React. – Dan.
Dan的twitter
Notice the answer he gives.
When you use the setState function…
Updates are put into a queue and executed in the order they are called.
Thus, when React encounters “multiple functional setState () calls,” React queues functions “in the order in which they are called,” rather than merging objects together (there are, of course, no objects to merge).
React then continues to update the state by calling each function in the “queue”, passing them to the previous state — i.e., The state before the first function setState () was called (if the first function setState () is currently executing) or the state of the last update of the previous function setState () call in the queue.
Next we’ll simulate a setState () method to give you an idea of what React is doing. Also, to reduce verbosity, we’ll use ES6. You can always write an ES5 version if you want.
First, let’s create a component class. Then, in it, we’ll create a fake setState () method. In addition, our component will have the increaseScoreBy3 () method, which will perform the multifunctional setState. Finally, we’ll instantiate the class as React does.
class User{
state = {score : 0};
//let's fake setState
setState(state, callback) {
this.state = Object.assign({}, this.state, state);
if (callback) callback();
}
// Multiple calls to the function setState
increaseScoreBy3 () {
this.setState( (state) = > ({score : state.score + 1})),this.setState( (state) = > ({score : state.score + 1})),this.setState( (state) = > ({score : state.score + 1}}}))const Justice = new User();
Copy the code
Note that setState also accepts an optional second argument, the callback function. If it is passed, React calls it after updating the state.
Now, when the user fires the increaseScoreBy3 (), React puts multiple functional setstates into the queue. We won’t fake that logic here, because our focus is on what really makes functional setState safe. But you can think of the result of the queuing process as an array of functions, as follows:
const updateQueue = [
(state) = > ({score : state.score + 1}),
(state) => ({score : state.score + 1}),
(state) => ({score : state.score + 1})];Copy the code
Finally, let’s simulate the update process:
// Call state updates recursively in order
function updateState(component, updateQueue) {
if (updateQueue.length === 1) {
return component.setState(updateQueue[0](component.state));
}
return component.setState(
updateQueue[0](component.state),
() =>
updateState( component, updateQueue.slice(1))); } updateState(Justice, updateQueue);Copy the code
Yes, it’s not great code, and you can certainly write better code. But the key point here is that every time React executes a function in the function setState, React updates your state by passing it a new copy of the updated state. This allows the function setState to set a new state based on the previous state. Here, I create a bin with complete code.
I’ll fill out the example so you can understand it better.
class User{
state = {score : 0};
//fake setState
setState(state, callback) {
console.log("state", state);
this.state = Object.assign({}, this.state, state);
if(callback) callback(); }}const Justice = new User();
const updateQueue = [
(state) = > ({score : state.score + 1}),
(state) => ({score : state.score + 1}),
(state) => ({score : state.score + 1})];// Call state updates recursively in order
function updateState(component, updateQueue) {
if (updateQueue.length === 1) {
return component.setState(updateQueue[0](component.state));
}
return component.setState(
updateQueue[0](component.state),
() =>
updateState( component, updateQueue.slice(1))); }Copy the code
Run this code to make sure you understand it. And when you come back we’ll see what really makes functional setState shine.
I’ll just tell you the secret
So far, we’ve delved into why it’s safe to execute multiple functional setStates in React. But we haven’t actually completed the full definition of functional setState: “Declare state changes separate from component classes.”
For years, the setting-state logic — that is, the function or object we pass to setState () — was always in the component class, which was more imperative than declarative.
So today, I show you a newly unearthed treasure – the Best React secret:
The address of this tweet
Thank you Dan Abramov!
This is the power of the functional setState. Declare status update logic outside the component class. It is then called in the component class.
// outside your component class
function increaseScore (state, props) {
return {score : state.score + 1}}class User{...// inside your component class
handleIncreaseScore () {
this.setState( increaseScore)
}
...
}
Copy the code
It’s declarative! Your component classes no longer care about status updates. It simply declares the type of update it wants.
To understand this, consider complex components that typically have many state slices, updating each slice in different operations. Sometimes, more than one line of code is required for each update feature. All of this logic will exist in your components. But not anymore!
Also, I like to keep each module as short as possible. If, like me, you feel that your current module is too long, you can extract all state change logic into other modules, then import it and use it in your component.
import {increaseScore} from ".. /stateChanges";
class User{...// inside your component class
handleIncreaseScore () {
this.setState( increaseScore)
}
...
}
Copy the code
You can now even reuse the increaseScore function in another component, simply by importing it.
What else can you do with the function setState?
Make testing easy!
The address of this tweet
You can also pass extra parameters to calculate the next state (this one blew my mind……)
The address of this tweet
Looking forward to more……
The future of the React
Hey, Dan! One last word (look ahead to React)?
The address of this tweet
If you’ve seen this, you’re probably as excited as I am. Start trying the function setState now!
Happy masturbation!