React Native State(状态)使用详解

BG:

目前的Component仍然在react框架中,也就是说React Native使用的Component是react框架中的组件,而Component有两大数据管理核心State和Props。也就是说即使你仅仅想用React Native开发APP,你也需要去了解React的相关知识,比如Component、State和Props,本文主要介绍State的使用。

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

一.初始化 this.state

在组件的 类构造函数(class constructor) 中初始化 this.state

export default class StatePage extends Component {
    constructor(props) {
        super(props);
        this.state = {  
            name : '张三',
            age:0,
         };
    };
}

注意:唯一可以分配 this.state 的地方是构造函数。

二、this.setState()

1.setState的原理:

image.png

这只是一个简单的原理图,setState背后的实现的详细过程需要借助React.js源代码和调用堆栈去查看。

2.setState引发的Component的更新过程:

setState会触发Component的以下4个生命周期方法,并依次执行:

shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

shouldComponentUpdate返回的是trueorfalse决定了当前组件是否在state或props改变后是否进行render。shouldComponentUpdate默认返回的是true,也就是当前组件在setState或props改变后会进行render,刷新UI。

3.this.state何时才被更新?

要想观察this.state何时被更新,需要我们去在相关生命周期方法中去进行打印,而观察的结果是这样的:

shouldComponentUpdate返回true时:

1.当shouldComponentUpdate函数被调用的时候,this.state没有得到更新;
2.当componentWillUpdate函数被调用的时候,this.state依然没有得到更新;
3.直到render函数被调用的时候,this.state才得到更新。

shouldComponentUpdate返回false时:

1.本次shouldComponentUpdate函数被调用的时候,this.state没有得到更新;
2.当shouldComponentUpdate函数返回false,此时更新过程会被中断,render函数也不会被调用,但这时候React不会放弃掉对this.state的更新的,所以虽然不调用render,依然会更新this.state,在下次触发shouldComponentUpdate时可以看到打印的this.state已经更新。

综上所述:直到render函数调用时(或者shouldComponentUpdate返回false,再次在shouldComponentUpdate函数中)才得到更新后的this.state。

三、setState使用:

执行setState时,会将需要更新的state合并后放入状态队列,而不会立刻更新state,队列机制可以批量更新state。

1. setState的几种场景:

(1).批量更新的典型,合并、异步setState:
clickBtn=()=>{
        this.setState({
            name:'王五',
        });
        this.setState({
            age:30
        });
      this.setState({
            age:20
        });
}

合并是浅合并,所以 第二次this.setState({age }) 不会把 this.state.name 冲掉,但会完全替换上一次this.state.age 的值。

以上代码只会触发1次render,并且在render函数调用时this.state.age的值才被更新且是20。也就是多次的setState会被合并,并且单个属性的多次setState只有最后一次的更新会生效。

(2).非批量更新的典型,定时器中setState:
componentWillMount() {
        console.log(`StatePage--componentWillMount`);
        this.testTimer = setTimeout(
            ()=>{
                    this.setState({
                        age: this.state.age + 1,
                     });
                     this.setState({
                        age: this.state.age + 1,
                     });

                     this.setState({
                        age: this.state.age + 1,
                     });
            },
            0,
          );
   }

以上代码会触发3次render,并且每次this.state.age的值都会加1。

定时器中setState,对应了上面setState的原理图中的非bathUpdate分支。

(3)、依赖this.props 和 this.state的值更新this.state:

因为 this.props 和 this.state 可能是异步更新的,你不能依赖他们的值计算下一个state(状态)。
错误写法:

    this.setState({
        age: this.state.age + this.props.baseAge,
     });

以上代码可能导致 age(年龄)更新失败!

正确写法:
setState()接收一个函数,而不是一个对象。该函数接收前一个状态值作为第 1 个参数,前一个props值作为第 2 个参数, 并将更新后的值进行回调,也就是利用上一次状态的age和props中的age进行计算来更新的age:

this.setState((state, props) => ({
        age: state.age + props.baseAge,
    }));

在上面使用了一个箭头函数,但是也可以使用一个常规的函数:

// 正确
this.setState(function(state, props) {
  return {
    counter:state.age + props.baseAge,
  };
});
(4)、setState回调函数:
this.setState({age: 23}, ()=> {
   console.log(this.state.age);//23
});

`setState的回调函数中可以获取到已经更新后的state,相当于componentDidUpdate函数或render函数中获取更新后的state。

四、数据自顶向下流动

无论作为父组件还是子组件,它都无法获悉一个组件是否有状态,同时也不需要关心另一个组件是定义为函数组件还是类组件。

这就是 state(状态) 经常被称为 本地状态 或 封装状态的原因。 它不能被拥有并设置它的组件 以外的任何组件访问。

一个组件可以选择将 state(状态) 向下传递,作为其子组件的 props(属性):

 <StateComponent name={this.state.name} age = {this.state.age}/>

子组件StateComponent通过 props(属性) 接收了父组件传递的name和age的值,但它仍然不能获知该值是来自于父组件的 state(状态) ,还是 父组件 的 props(属性),或者是父组件中直接手动创建的。

五、总结:

1.不要使用 this.state 来直接修改 state,state值虽然会被更改,但不会触发render;
2.setState可能是异步的,不会立刻改变React组件中state的值;
3.React 为了优化性能,有可能会将多个 setState() 调用合并为一次更新
4.setState通过引发一次组件的更新过程来引发重新绘制;
5.不能依赖this.props 和 this.state的值计算下一个state(状态);
6.定时器中多次setState不会被合并,state的值会被立即更新;
7.setState可能会引发不必要的渲染,你可以在shouldComponentUpdate(object nextProps, object nextState)函数中根据实际情况决定是否触发render。

推荐阅读更多精彩内容

  • 作为一个合格的开发者,不要只满足于编写了可以运行的代码。而要了解代码背后的工作原理;不要只满足于自己的程序...
    六个周阅读 7,136评论 1 32
  • 40、React 什么是React?React 是一个用于构建用户界面的框架(采用的是MVC模式):集中处理VIE...
    萌妹撒阅读 607评论 0 1
  • 说在前面 关于 react 的总结过去半年就一直碎碎念着要搞起来,各(wo)种(tai)原(lan)因(le)。心...
    陈嘻嘻啊阅读 6,102评论 7 41
  • 使用 create-react-app 快速构建 React 开发环境 项目的目录结构如下: React JSX ...
    majun00阅读 221评论 0 0
  • 根据共读计划,本周(6.18-6.24)我通过电子书阅读了《番茄工作法图解-简单易行的时间管理法》的前三章...
    墨蓝色彩阅读 85评论 0 0