React的setState学习及应用
一:作用:
setState()
将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式。
二: 特性
1、为了更好的感知性能,React 会延迟调用它,然后通过一次传递更新多个组件。React 并不会保证 state 的变更会立即生效。批量推迟更新:setState()
是异步的,并且在同一周期内会对多个 setState
进行批处理,后调用的 setState()
将覆盖同一周期内先调用 setState
的值。
import React, {Component} from 'react'; export default class Test extends Component { constructor(props) { super(props); this.state = { a: 0, b: 0, } } componentDidMount() { } onClick = () => { this.setState({ a: this.state.a + 1 }) this.setState({ a: this.state.a + 1 }) this.setState({ b: this.state.b + 1 }) } render() { console.log('重新渲染', `a=${this.state.a}`, `b=${this.state.b}`); return ( <div onClick={this.onClick}>按钮</div> ) } }
打印结果为:
2: 在调用 setState()
后立即读取 this.state,请使用
componentDidUpdate
或者 setState
的回调函数(setState(updater, callback)
),这两种方式都可以保证在应用更新后触发。
使用updater函数 (updater 函数中接收的 state
和 props
都保证为最新):
onClick = () => { this.setState((state, props) => { return { a: state.a + 1, b: state.b + 1, } }) this.setState((state, props) => { return { a: state.a + 1, b: state.b + 1, } }) }
打印结果为:
这里并没有打印两次,说明updater函数也是批量推迟更新。
使用回调函数: setState()
的第二个参数为可选的回调函数,它将在 setState
完成合并并重新渲染组件后执行。通常,我们建议使用 componentDidUpdate()
来代替此方式。
onClick = () => { this.setState({ a: this.state.a + 1, b: this.state.b + 1, }, () => { this.setState({ a: this.state.a + 1, b: this.state.b + 1, }) }) }
打印结果为:
使用componentDidUpdate()。此生命周期和render()一样,都不能在内部使用setstate方法,不然会导致死循环,只能读,不能改。
componentDidUpdate() { console.log('重新渲染结束', `a=${this.state.a}`, `b=${this.state.b}`); } onClick = () => { this.setState({ a: this.state.a + 1, b: this.state.b + 1, }) }
打印结果为:
三:setstate是异步还是同步?
有时表现出异步,有时表现出同步
1、setState
只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout
中都是同步的。
2、setState
的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback)
中的callback
拿到更新后的结果。
3、setState
的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新。
settimeout
onClick = () => { setTimeout(() => { this.setState({ a: this.state.a + 1, b: this.state.b + 1, }) this.setState({ a: this.state.a + 1, b: this.state.b + 1, }) }) }
打印结果为:
原生事件:
componentDidMount() { const btn = document.getElementById('btn'); btn.addEventListener('click', this.onDomClick, false) } onDomClick = () => { this.setState({ a: this.state.a + 1, b: this.state.b + 1, }) this.setState({ a: this.state.a + 1, b: this.state.b + 1, }) } render() { console.log('重新渲染', `a=${this.state.a}`, `b=${this.state.b}`); return ( <div id='btn'>按钮</div> ) }
打印结果为: