React Native State(状态)使用详解

作者: 星辰大海_王 | 来源:发表于2019-01-20 13:05 被阅读2次

    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。

    相关文章

      网友评论

        本文标题:React Native State(状态)使用详解

        本文链接:https://www.haomeiwen.com/subject/cykxjqtx.html