setState
更新数据
- setState是异步更新数据的
- 注意: 使用该语法时,后面的setState()不要依赖于前面的setState()
- 可以多次调用setState(),只会触发一次重新渲染
this.state = { count: 1 }
this.setState{{
count: this.state.count + 1
}}
console.log(this.state.count)//1
推荐语法
- 推荐:使用setState((state,props)=>{})语法
- 参数state:表示最新的state
- 参数props:表示最新的props
this.setState((state,props) => {
return {
count: state.count + 1
}
})
console.log(this.state.count)//1
这个语法也只会触发一次更新
第二个参数
- 场景:在状态更新(页面完成重新渲染后)立即执行某个操作
- 语法:setState(update[,callback])
this.setState(
(state,props) => {},
() => {console.log('这个回调函数会在状态更新后立即执行')}
)
- 使用推荐语法第二个参数,可以在回调函数里面依赖前面的setState()
state = {
count: 1
}
...
this.setState(
(state,props) => {
return {
count: state.count + 1
}
},
() => {
console.log('状态更新完成',this.state.count)//状态更新完成: 2
}
)
console.log(this.state.count)//1
...
JSX语法的转化过程
- JSX仅仅是createElement()方法的语法糖(简化语法)
- JSX语法被@babel/preset-react插件编译为createElement()方法
- React元素: 是一个对象,用来描述你希望在屏幕上看到的内容
graph LR
JSX语法 --> createElement --> React元素
JSX语法
const element = (
<h1 className="greeting">
Hello JSX!
</h1>
);
createElement
const element =
React.createElement(
'hi',
{className: 'greeting'},
'Hello JSX!'
);
React元素
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello JSX!'
}
};
组件更新机制
- setState()的两个作用:1.修改state 2.更新组件(UI)
- 过程:父组件重新渲染时,也会重新渲染子组件,但只会渲染当前组件子树(当前组件及其所有子组件)
组件性能优化
减轻state
- 减轻state:只储存跟组件渲染相关的数据(比如:count/列表数据/loading等)
- 注意:不用做渲染的数据不要放在state中,比如定时器id等
- 对于这种需要在多个方法中用到的数据,应该放在this中
class Hello extends Component {
componentDidMount() {
//timerId存储到this中,而不是state中
this.timerId = setInterval(() => {}, 2000)
}
componentWillUnmount() {
clearInterval(this.timerId)
}
render() { ... }
}
避免不必要的重新渲染
- 组件更新机制:父组件更新会引起组件也被更新,这种思路很清晰
- 问题:子组件没有任何变化时也会重新渲染
- 如何避免不必要的重新渲染呢?
- 解决方式:使用**钩子函数 shouldComponentUpdate(nextProps,nextState)
- 作用:通过返回值决定该组件是否重新渲染,返回true表示重新渲染,false表示不重新渲染
- 触发时机:更新阶段的钩子函数,组件重新渲染前执行(shouldComponentUpdate—>render)
class Hello extends Component {
shouldComponentUpdate() {
//根据条件,决定是否重新渲染组件
return false
}
render() { ... }
}
纯组件
- 说明:纯组件内部的对比是shallow compare(浅层对比)
- 对于引用类型来说:只比较对象的引用(地址)是否相同
- 注意:state或props中属性值为引用类型时,应该创建新数据,不要直接修改原数据!
虚拟DOM
执行过程
- 初次渲染时,React会根据初始state(Model),创建一个虚拟DOM对象(树)。
- 根据虚拟DOM生成真正的DOM,渲染到页面。
- 当数据变化后(setState()),重新根据新的数据,创建新的虚拟DOM对象(树)。
- 与上一次得到的虚拟DOM对象,使用Diff算法对比(找不同),得到需要更新的内容。
- 最终,React只将变化的内容更新(patch)到DOM中,重新渲染到页面。