11、React系列之--state状态

版权声明:本文为博主原创文章,未经博主允许不得转载。

PS:转载请注明出处
作者:TigerChain
地址:http://www.jianshu.com/p/44a787904d9b
本文出自TigerChain简书

React 教程系列

教程简介

  • 1、阅读对象

本篇教程适合新手阅读,老手直接略过

正文

注:本篇文章采用ES6的写法,以后不没有特别说明都使用ES6+yarn+webpack去写demo

1、什么是state

我们都说React是一个状态机,体现是什么地方呢,就是体现在state上,通过与用户的交互,实现不同的状态,然后去渲染UI,这样就让用户的数据和界面保持一致了。state是组件的私有属性。

在React中,更新组件的state,结果就会重新渲染用户界面(不需要操作DOM),一句话就是说,用户的界面会随着状态的改变而改变。

PS: state 只能在本组件中去初始化,并且 state 只能被本组件去修改和仿问,不能被外部仿问和修改,所以也可以说,state 是组件私有的。

2、state的使用方法

1、初始化state

对于state的使用方法,在ES5中和Es6中使用是不一样的,我们以ES6为例,在组件的构方法中如下设置即可,设置一个默认的state属性。

constructor(props) {
   super(props);
   this.state={
      key:value,
      ...
   }
}

2、更新state

更新state调用以下方法

 this.setState({
     key:value
 }) ;

千万不要这么干,this.state.key = XXX ; 这样不会重新渲染界面

注意:setState()是异步的,也就是你调用了setState()之后,React就开始准备去更新了,中间计算会可能会有一定的延时。

PS:如果调用了setState()方法以后,就会调用render()方法,也就是前面说的,用户的界面会随着状态的改变而改变。

3、调用diff算法

这一步是在2步的基础上的,setState()会触发diff算法最终确定是否要更新。

3、什么样的组件应该有state

应该说大部分的组件根据props来取得数据并渲染,但是用户输入,请求服务器,操作数据库等情况下就需要state了.官方的建议是尽量构建无状态的组件,是为了提高性能,减少渲染次数,做法就是构建几个无状态的组件,在这之上构建一个有状态和用户和服务交互 ,然后通过props来传递给无状态的组件。

使用state要注意三个事情

  • 1、不要直接的修改state
反例  请不要这样做
this.state.comment = 'Hello';

正确的做法是使用setState()方法

正确的做法
this.setState({
    comment:'Hello',
})
  • 2、状态更新是异步的

用官方的话说就是this.props和this.state更新的时候可能是异步的,所以你不应该依靠他们的值来计算下一个状态

以下是错误的例子

反例
this.setState({
  counter: this.state.counter + this.props.increment,
});

正确的例子

正确的例子
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}))
  • 3、state的更新是合并后的

当你调用 setState() ,React会合并你提供的对象到当前的 state 里

比如:你的state可能包含几个独立的变量

constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

然后你可以通过调用setState()来独立的更新他们

componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

这个合并是浅合并,所以 this.setState({comments}) 会让 this.state.posts 完整,但是会完全替换掉 this.state.comments .

4、开始撸码

说一千,道一万,都是在理论级别,下面我们从0开始写一个简单的Demo来体验一下state。下面使用webpack+yarn来写一个demo。

在mac环境下,win下基本差不太多

1、在指定目录下新建state目录(命令行中操作)

mkdir state

2、使用yarn初始化项目(命令行中操作)

cd state
yarn init

在上面步骤一路回车即可

3、安装一些依赖(命令行中操作)

yarn add react react-dom webpack webpack-dev-server babel-core babel-loader babel-preset-react bable-preset-es2015 babel-preset-stage-0 --dev

然后回车,等待安装依赖,如果没有什么问题就可以在package.json中看到如下结果(红色框中)

state-package.png

以上就表明你的依赖安装成功了

4、在state根目录中新建.babelrc并输入以下内容

{
  "presets":["react","es2015","stage-0"]
}

5、在state目录中分别新建app和public文件夹

state-app-public.png

6、在public中新建index.html并输入以下内容

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Hello state</title>
</head>
<body>

  <div id="container"></div>
  <script src="bundle.js"></script>
</body>
</html>

7、在app目录中分别新建main.js和State.js

# main.js

import React from 'react' ;
import ReactDOM from 'react-dom' ;

import State from './State.js' ;
ReactDOM.render(
  <State />,
  document.getElementById('container')
) ;

# State.js
import React, { Component, PropTypes } from 'react';

/**
 * 使用es6语法 定义一个State组件
 */
export default class State extends Component {

  constructor(props) {
    super(props);
    this.state = { //初始化state
      countnum:0,
    };
  }

  /**
   * 点击事件方法 countnum+1
   */
  _handlerEvent(){
    this.setState({
      countnum:this.state.countnum+1,
    })
  }
  render() {
    return (<div>
      {this._renderView()}
    </div>);
  }
  /**
   * 渲染一个button组件
   */
  _renderView(){
    return(
      <div>
        <button onClick={this._handlerEvent.bind(this)}>点击{this.state.countnum}次</button>
      </div>
    );
  }
}

8、在state根目录中新建webpack.config.js并且输入以下内容,具体不清楚的可以看webpack这一节:http://www.jianshu.com/p/732c4d501668

module.exports = {
  entry:__dirname+'/app/main.js',
  output:{
    path:__dirname+'/public',
    filename:'bundle.js'
  },
  devServer:{
     contentBase: "./public",//本地服务器所加载的页面所在的目录
     historyApiFallback: true,//不跳转
     inline: true//实时刷新
   },
  module:{
    loaders:[
    //babel配置
    {
      test:/\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }
  ]
  }
}

9、在package.json中添加脚本(这不是必须的,但是可以方便调用)

script-webpack.png

图中的蓝色部分就是我们添加的脚本,即:

"scripts":{
    "start":"webpack-dev-server --progress --port 8888"
 }

10、在命令行直接运行 yarn start 如果没有什么问题,我们在浏览器上输入localhost:8888,会看到下面的结果

count.gif

以上我们就完成了一个简单的state的例子,从这个例子中我们可以看到每当我点击按钮的时候组件的状态都会发生改变,计数就加1了,但是当我们调用了setState()方法到底有没有刷新界面呢?我们再测试一下

11、接着上面的例子我们继续修改State.js

render-test.png

从图中可知我们只是在原有的基础上添加了现代战争方法,用来测试render方法调用次数,然后保存,看结果(打开chrome的调试栏)

render-state.gif

从图中我们可以清楚的看到,我们点击了多少次,render方法就调用了多少次,所以说当调用了setState()方法就会重新渲染界面

到此为止,我们对state就有一个大体的认知了。下面我们来说一个无状态组件的例子。

5、无状态的组件

1、什么是无状态组件

无状态组件顾名思义就是没有状态的组件我们上面提到过无状态的组件,官方建议的是尽量让组件无状态化,但是肯定有一个地方要状态化的,一般做法是把要组合的组件无状态化,宿主组件有一个状态设置(一般情况下,也就是父组件更新子组件的时候,但是有时会反过来)

接下来我们构建一个无状态的组件,然后通过和用户交互(点击)的时候把状态通过props传给无状态的组件达到更新UI的目的,这么说可能有点绕我们看下面图来直观的理解一下

state_less.png

上图就是这一过程的一个伪代码,很好理解。

2、我们通过一个demo来直观感受一下

1、接着上面的例子,我们继续在app中分别新建PassStateOfprops.js和StateLess.js

# PassStateOfprops.js  此组件可以当作有状态的父组件

import React, { Component, PropTypes } from 'react';

import StateLess from './StateLess.js' ;

/**
 * 通过 props来传递state 达到更新组件的目的
 */
export default class PassStateOfprops extends Component {
  constructor(props) {
    super(props);
    this.state = {  //初始化state
      list:[
        '111',
        '222',
        '333'
      ]
    }
  }

  /**
   * 渲染界面
   */
  render() {
    return (<div>
      {this._renderButton()}
      {/* 将state通过props传递到无状态组件StateLess中 */}
      <StateLess datas={this.state.list}/>
    </div>);
  }

/**
 * 渲染一个button
 */
  _renderButton(){
    return(
      <div>
        <button onClick={this._handlerEvent.bind(this)}>改变值</button>
      </div>
    ) ;
  }

  /**
   * 点击事件
   */
  _handlerEvent(){
    this.setState({
      list:['444','555','666']
    }) ;
  }
}

#  StateLess.js  定义一个无状态的组件

import React, { Component, PropTypes } from 'react';

/**
 * 定义一个无状态的组件
 */
export default class StateLess extends Component {

  render() {
    return (<div>
      <ul>
        {
          this.props.datas.map(function (data) {
            return (
              <li>{data}</li>
            )
          })
        }
      </ul>

    </div>);
  }
}

2、修改main.js中代码

test-stateless.png

其中黄色部分就是我们修改的部分.

3、查看结果

state-less.gif

我们看到通过props传递state到无状态的组件成功运行了,所以我们以后在项目中开发,尽量使用无状态化的组件,把这种思想和习惯从现在就养成。

本demo的地址

https://github.com/tigerchain/react-lesson/tree/master/lesson02/09-state

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

推荐阅读更多精彩内容

  • 最近看了一本关于学习方法论的书,强调了记笔记和坚持的重要性。这几天也刚好在学习React,所以我打算每天坚持一篇R...
    gaoer1938阅读 1,615评论 0 5
  • 原教程内容详见精益 React 学习指南,这只是我在学习过程中的一些阅读笔记,个人觉得该教程讲解深入浅出,比目前大...
    leonaxiong阅读 2,771评论 1 18
  • 抄写于2017年10月30日。虽说字体还幼稚,但好歹自己是爬过了提笔惧怕,难成完整作品的尴尬时期。越是太过追求完美...
    末年末世阅读 116评论 0 0
  • 英国BBC电视台拍摄过一部记录片——《7UP》,片中追踪了14个来自于各个社会阶层的孩子。 从他们7岁开始,每隔七...
    lil_lin阅读 1,117评论 0 6
  • 我们曾如此渴望命运的波澜,到最后才发现:人生最曼妙的风景,竟是内心的淡定与从容。我们曾如此期盼外界的认可,到最后才...
    苏嗒嗒阅读 276评论 2 0