//index.js
import React from "react";
import ReactDOM from "react-dom";import Counter from "./counter.js";ReactDOM.render(<Counter caption="计数器"/>,document.querySelector('#root')
)
//counter.js
import React from "react";const style = {
marginRight:"5px"
}
class Counter extends React.Component{
constructor(props){
super(props);this.state = {
count:0}this.handleIncrement = () => {
this.setState((state,props) => {
console.log(props);return {
count:state.count+1}},()=>{
console.log("当前计数:",this.state.count);})}this.handleDecrement = () => {
this.setState({
count:this.state.count-1}, () => {
console.log("当前计数:",this.state.count)})}}render(){
return (<><h3>{
this.props.caption}</h3><button style={
style} onClick={
this.handleIncrement}>+</button><button style={
style} onClick={
this.handleDecrement}>-</button><span>{
this.state.count}</span></>);}
}export default Counter;
setState
完成了两项工作:
- 更新state对象
- 驱动组件渲染,引发componentDidUpdate、render等函数调用
setState
有两种使用方式:
setState(updater,callback)
第一个参数,updater,是函数,用来返回新的state对象;
第二个参数,callback,是回调函数,state改变且渲染完成后callback会被调用。
updater有两个参数:state和props。
state 是 最新state(可能不太准确); props 是 从父组件传递过来的props。setState(stateChange,callback)
第一个参数,stateChange,是一个新的state对象;
第二个参数,callback,是回调函数,state改变且渲染完成后callback会被调用。
setState
并不总会立即更新this.state
,可能同步,也可能异步。
import React from "react";const style = {
marginRight:"5px"
}
class Counter extends React.Component{
constructor(props){
super(props);this.state = {
count:0}this.handleIncrement = () => {
this.setState((state,props) => ({
count:state.count+1}));this.setState((state,props) => ({
count:state.count+1}));this.setState((state,props) => ({
count:state.count+1}));// this.setState((state,props) => {
// console.log("this.state.count:",this.state.count," ","state.count:",state.count);// return { count:state.count+1 }// })// this.setState((state,props) => {
// console.log("this.state.count:",this.state.count," ","state.count:",state.count);// return { count:state.count+1 }// })// this.setState((state,props) => {
// console.log("this.state.count:",this.state.count," ","state.count:",state.count);// return { count:state.count+1 }// })}this.handleDecrement = () => {
this.setState({
count:this.state.count-1});this.setState({
count:this.state.count-1});this.setState({
count:this.state.count-1});// this.setState({count:this.state.count-1}); console.log("this.state.count:",this.state.count);// this.setState({count:this.state.count-1}); console.log("this.state.countt:",this.state.count);// this.setState({count:this.state.count-1}); console.log("this.state.count:",this.state.count);}}static getDerivedStateFromProps(nextProps,nextState){
console.log("enter getDerivedStateFromProps","nextState:",nextState);return null;}shouldComponentUpdate(nextProps,nextState){
console.log("enter shouldComponentUpdate");return true;}render(){
console.log("enter render");return (<><h3>{
this.props.caption}</h3><button style={
style} onClick={
this.handleIncrement}>+</button><button style={
style} onClick={
this.handleDecrement}>-</button><span>{
this.state.count}</span></>);}
}export default Counter;
本例,调用setState
时,this.state
没有立即更新,到了 调用render
时 才会更新,属异步更新。
多次调用setState
,setState(updater,callback)
、setState(stateChange,callback)
都会有个合并的过程,但合并方式不同,因而最终的this.state.count
不一样。不过,不论以何种方式 setState
,组件都只会渲染一次。
import React from "react";const style = {
marginRight:"5px"
}
class Counter extends React.Component{
constructor(props){
super(props);this.state = {
count:0}this.handleIncrement = () => {
this.setState(state => ({
count:state.count+1}));console.log("setState in onClick","this.state.count:",this.state.count);}this.handleDecrement = () => {
setTimeout(() => {
this.setState(state => ({
count:state.count-1}));console.log("setState in setTimeout","this.state.count:",this.state.count);})}this.handleClickA = () => {
this.setState(state => ({
count:state.count+1}));console.log("setState in EventListener","this.state.count:",this.state.count);}this.handleClickB = () => {
new Promise(resolve => {
this.setState(state => ({
count:state.count-1}));resolve(this.state.count);}).then(count => {
console.log("setState in Promise","this.state.count",count);})}}componentDidMount(){
document.querySelector('#testA').addEventListener("click",this.handleClickA);document.querySelector('#testB').addEventListener("click",this.handleClickB);}componentWillUnmount(){
document.querySelector('#testA').removeEventListener("click",this.handleClickA); document.querySelector('#testB').removeEventListener("click",this.handleClickB); }render(){
console.log("enter render","this.state.count:",this.state.count);return (<><h3>{
this.props.caption}</h3><button style={
style} onClick={
this.handleIncrement}>+</button><button style={
style} onClick={
this.handleDecrement}>-</button><button style={
style} id='testA'>+(test)</button><button style={
style} id='testB'>-(test)</button><span>{
this.state.count}</span></>);}
}export default Counter;
addEventListener
里调用setState
,同步更新了this.state
;
setTimeout
里调用setState
,同步更新了this.state
;
Promise
里调用setState
,同步更新了this.state
;
React事件处理程序的setState
,异步更新了this.state
,这是因为React事件处理程序中的更新 默认会被批量处理。
参考文章
setState:这个API设计到底怎么样
何时以及为什么 setState() 会批量执行?
React 是否保持 state 更新的顺序?