组件的状态
react hook出来之前,函数式组件是没有自己状态的。
jsx 就和原生js编写差不多,所有就当作在定义类,在类方法中使用变量,就要通过this来调用。
主义要写在state中,数据驱动视图,我们想要修改视图无需操作dom,通过setState方法来修改state中的变量。这个可以理解为单向的和vue一样。所谓dom操作想要修改自己显示,还是通过修改数据来实现,所以所有数据驱动的框架,都不用我们自己来渲染dom,框架内部虚拟dom性能更高,我们只用关注数据层即可。
不要直接修改state中的值,必须通过setState方法进行修改
import React from "react"
class HelloC extends React.Component {
//初始状态
state = {
count: 10
}
setCount = () => {
this.setState({
count:this.state.count + 1
})
}
render () {
return (
<div>这是我的第一个类组件! <span onClick={this.setCount}>读取我的属性count: {this.state.count}</span></div>
)
}
}
这里的setCount方法 使用的箭头函数,如果不使用箭头函数我们就需要绑定this,
class Foo extends React.Component { handleClick () { this.setState({ xxx: aaa }) } render() { return ( <button onClick={this.handleClick.bind(this)}> Click me </button> ) } }
为何需要手动绑定this,记住我们传入的是一个方法,this.handleClick,而并非执行,只有在执行代码时才会为我们绑定this,所以执行时的this早已不是Foo,bind绑定在执行前将foo当作this传入。
此时this指向Helloc,如果直接调用方法handleClick,里边this肯定是Helloc 但是只是传入方法未调用
其他方式:
https://juejin.cn/post/6844904200996913160
主流的写法已经变成了class fields,无需考虑太多this问题
页面直接打印 对象
- 原因
写React的render()
时,想直接查看整个state
对象的内容,就写了{this.state}
,然后报错。
原因是不能直接往{}
里放Object
- 解决
把放入{}
中的变量,格式变为非Object即可。两种方法:
JSON.stringify(xxx)
可以将任意变量字符串化,包括对象格式(但要防止对象的循环引用)。
多写点代码,原本直接传入一个对象,修改为:一个成员一个成员地传入,如{this.state.name} {this.state.age}
这点和vue不大一样,vue是可以直接打印对象查看的。
React的状态不可变
不要直接修改状态值,而是基于当前状态创建新的状态值。
这叫什么来着,就是比如我们封装一些方法,方法有传入的参数,一个好的方法,应该不会修改传入的参数原始值,如果传入一个引用,修改参数原本对象也会修改.所有我们一般将传入引入数据类型拷贝一份。
import React from "react"
class HelloC extends React.Component {
//初始状态
state = {
count: 10,
list: [1, 2, 3],
person: {
name: 'jack',
age: 18
}
}
handleClick () {
console.log(this) //undefined
this.setState({ count: this.state.count + 1 })
}
setCount = () => {
this.setState({
count: this.state.count + 1
})
}
//基于当前状态创建新值
newStatus = () => {
this.setState({
count: this.state.count + 1,
list: [...this.state.list, 4],
person: {
...this.state.person,
// 覆盖原来的属性 就可以达到修改对象中属性的目的
name: 'rose'
}
})
}
render () {
return (
<div>
<div>这是我的第一个类组件! <span onClick={(e) => this.handleClick(e)}>读取我的属性count: {this.state.count}</span></div>
<div>这是我的第一个类组件! <span onClick={this.setCount}>读取我的属性count: {this.state.count}</span></div>
<div>这是我的第一个类组件! <span onClick={this.newStatus}>读取我的属性count: {this.state.list}{JSON.stringify(this.state.person)}</span></div>
</div>
)
}
}
构造函数是唯一可以给
this.state
赋值的地方。React 的状态不可变本质上是引用不可变,因为对于 JavaScript 来说,对象是一种引用类型。在你
setState
后,React 会对新旧两个状态进行浅比较,因为state
是引用类型,所以 React 会比较新旧state
的引用,只有比较结果为false
,才会进行重新渲染。所以说,你每次
setState
替换新的对象,其实质是替换对象的引用,让 React 感知到state
的变化,React 才会进行重新渲染。官方文档:https://reactjs.org/docs/optimizing-performance.html#avoid-reconciliation
说实话感觉和vue不能检测到data里对象属性改变一样,vue里通过set方法来告知vue进行重新渲染。
而react直接将整个对象重新赋值这样,检测到对象改变,整个肯定会重新渲染,感觉性能没有提升继续往后看吧
当你调用
setState()
的时候,React 会把你提供的对象合并到当前的 state。这里合并仅仅是浅合并,也就是只合并第一层
React源码中,使用了
Object.assign()
方法,对preState和更新后的State做了一个合并。