1. Simple and complex components
Simple component: no state
Complex component: state
So what is state?
2. state
In fact, the title is: the three core attributes of components (instances).
Only class components have instances, and functional components are not qualified at all. In order to solve the problem of functional components, react introduced hooks.
Use of state: let's take an example and click to change whether the weather is hot or cool
2.1 creating components
Do we want to create class components or functional components?
Class components, of course.
// 1. Create class components class Weather extends React.Component{ render(){ console.log(this) return <h2>It's very hot today</h2> } } // 2. Rendering ReactDOM.render(<Weather/>, document.getElementById('root'))
Then we need to define a variable isHot to change whether it is hot or cool. State is on an instance of the class. If we want to add variables to state and initialize the class instance, we need to write a constructor.
class Weather extends React.Component{ constructor(???){ } render(){ console.log(this) return <h2>It's very hot today</h2> } }
2.2 adding constructors
So what parameters need to be passed in the constructor? This depends on the parameters passed by the instance object. However, this is created by React and we can't see it.
We went to the official website and it passed props. Do you need to write super? Yes, this is the type of regulation.
// 1. Create class components class Weather extends React.Component{ constructor(props){ super(props) } render(){ console.log(this) return <h2>It's very hot today</h2> } }
2.3 adding variables / attributes
state to be written as an object
constructor(props){ super(props) this.state = { isHot:true } }
Now there is our isHot in the state on the instance object
Next, we just need to take out this value and render it
// 1. Create class components class Weather extends React.Component{ constructor(props){ super(props) this.state = { isHot:true } } render(){ console.log(this) return <div> <h2>It's a fine day today { this.state.isHot ? 'scorching hot':'pleasantly cool' } </h2> </div> } }
2.4 change the state value setState
Click the button to change the value
2.4. 1 original writing
Add id attribute to h2 tag. Use method: addEventListener or onClick
// Modular syntax in ES6 import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; // 1. Create class components class Weather extends React.Component{ constructor(props){ super(props) this.state = { isHot:true } } render(){ console.log(this) return <div> <h2 id="title">It's a fine day today { this.state.isHot ? 'scorching hot':'pleasantly cool' } </h2> </div> } } // 2. Rendering ReactDOM.render(<Weather/>, document.getElementById('root')) // Native method 1 const title = document.getElementById("title") title.addEventListener('click',()=>{ console.log("The title was clicked") } // Native method 2 title.onClick=()=>{ console.log("The title was clicked") }
Although the two methods can realize click events, they both use React to write as few native js methods as possible.
2.4. 2 write it in the label
This, of course, is also a native method. We write a new button tag and add onclick inside. Then write a demo method.
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; // 1. Create class components class Weather extends React.Component{ constructor(props){ super(props) this.state = { isHot:true } } render(){ console.log(this) return <div> <h2 id="title">It's a fine day today { this.state.isHot ? 'scorching hot':'pleasantly cool' } </h2> <button onclick="demo()">change weather</button> </div> } } // 2. Rendering ReactDOM.render(<Weather/>, document.getElementById('root')) function demo(){ console.log("The button was clicked") }
We will find that it reports an error because onclick cannot be used. So what do we use? Use onclick and React to turn the original events into hump rules.
So we have to change it to
<button onClick="demo()">change weather</button>
2.4. 3. Does the function need parentheses
We found that the "button is clicked" has been printed without clicking
So why? React helps us create a Weather instance and calls render through the instance. The < button onClick="demo()" > change Weather < / button > code is executed. To assign the return value of the function, onClick="demo()" is an assignment statement. Assign the return value on the right to onClick as a callback. What is the return value of the demo function? It's undefined. Clicking now has no effect.
Therefore, you need to delete the parenthesis onClick="demo", which means that the function on the right is given to the onClick event as a callback, and the function will be called only when it is clicked
Now click the button again to achieve the effect we want.
2.4. 4 change the value of isHot in the demo function
We deconstruct the assignment and get isHot
function demo(){ const {isHot} = this.state console.log(isHot) }
It was found that the report was wrong. state is not defined, so what is the root cause? It's this.
Why is there no this?
First of all, this function is our custom function, and Babel is in strict mode when converting our jsx to js. It does not allow this of a custom function to point to window.
🤔 What if we can't get the instance object of the component in our custom demo function?
We define a that variable in the outermost part, and then assign this, that is, the instance object, to that in the constructor. Finally, print that in the function
Although this is achieved, it is not perfect.
We put the demo method into the class and found that the function reported an error, because it can't be written in the class.
Just remove function
Now the demo is placed on the prototype object of the class for use by the instance object.
When a demo is called through a Weather instance, this in the demo is the Weather instance.
You don't need that at this time. Now an error will be reported. The demo function is undefined. Because the demo is under the instance object, you need this demo
After clicking, an error will still be reported because this is undefined
2.4. 5 this point of user-defined function
At this time, onClick={this.demo} does not call the demo method at all, but finds the demo along the prototype chain through the instance object of the class, and then gives this function to onClick as a callback. Calling functions directly from the heap is not invoked from the instance object at all. Methods in the class turn on local strict mode by default. Therefore, this is undefined at this time.
Using bind
this.demo = this.demo.bind(this)
- In essence, it is an assignment statement. First look at the right. In fact, there is no demo in the instance, so why not report an error? It will find the function on the prototype according to the prototype chain, which will find the function we defined.
- Once the code on the right is run, there will be a function, and this of this function successfully becomes the instance object of Weather.
- On the left, we put this function in the instance itself and give it a name, this demo.
At this point, when we print this in the function, we will find that we also have a demo method. So is each click and call executed by itself or on the prototype 🤔 ? According to the prototype chain, you have found it on yourself, so you won't find it on the prototype again.
Can the demo method on the prototype be deleted 🤔 ? Of course not. Because there is a demo method on the prototype, we can generate a new instance and hang it on the instance itself.
2.4.6 setState⁄
Get the value of the original isHot in the demo function. And reverse it and assign it back.
demo(){ const {isHot} = this.state this.state.isHot = !isHot } }
No change in how you click. So let's print out the console Log (this. State. Ishot) found that the value did change
The isHot value has changed, but the page does not change. Let's take a look at the react developer tool. No matter how we click on this value, it remains the same. React does not recognize our operation.
⚠️ : The status cannot be changed directly. API: setState is required
this.state.isHot = !isHot is ❌ How to write. The following is correct.
demo(){ const {isHot} = this.state this.setState({isHot:!isHot}) }
Then think about it 🤔
Is this setState merged or overwritten?
Let's add a wind variable to state. When changing isHot, whether the value of wind is lost or not is merging, otherwise it is overwriting.
this.state = { isHot:true, wind:"wind" } demo(){ const {isHot} = this.state this.setState({isHot:!isHot}) console.log(isHot) }
So it's a merger.
3. Streamline code
3.1 remove the constructor
Why write constructors?
Because some initialization operations need to be done. Do you feel like there's no place to write it in the constructor.
Class can write assignment statements directly. Therefore, assigning a value to state does not have to be written in the constructor.
state = { isHot:true, wind:"wind" }
You can find it undefined again. Because the demo function is placed on the prototype object of Weather.
3.2 transformation of user-defined functions
First, most of our custom methods are used as event callbacks.
Let's change this function: now it's an assignment statement. Now the demo is placed on the Weather instance itself, not on the prototype.
demo = function(){ const {isHot} = this.state this.setState({isHot:!isHot}) console.log(isHot) }
We clicked again, but it still didn't solve the problem.
Next, we replace the function with an arrow function. I found it.
demo=()=>{ const {isHot} = this.state this.setState({isHot:!isHot}) console.log(isHot) }
🤔 So why that?
- There is no this in the arrow function. Will an error be reported if this is used in the arrow function? No, he'll look for this in its outer function
To use. Find the outside, and you'll find the area inside the class. - Can we print this in the blank area? You can see that the error has been reported. Because this is a class, you can't write code casually.
So what do we think of this in the blank area? Can't see it? We just said that this in the arrow function is the point of this in its outer layer. So this we print in the arrow function is this in the blank area. It can be found that it is an instance object of the component.
3.3 complete code
After simplification, there is no need to write a constructor. The user-defined method should use the form of assignment statement + arrow function
class Weather extends React.Component{ state = { isHot:true, wind:"wind" } render(){ console.log(this) return <div> <h2>It's a fine day today { this.state.isHot ? 'scorching hot':'pleasantly cool' } </h2> <button onClick={this.demo}>change weather</button> </div> } demo=()=>{ const {isHot} = this.state console.log(this,"this") this.setState({isHot:!isHot}) console.log(isHot) } }