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。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,646评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,979评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,391评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,356评论 0 215
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,740评论 3 293
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,836评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,022评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,764评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,487评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,728评论 2 252
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,200评论 1 263
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,548评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,217评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,134评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,921评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,919评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,766评论 2 274

推荐阅读更多精彩内容

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