这集要聊的是另外一个 React 最重要的概念之一,也就是 State ,状态。 State 跟前面提过的属性 Props 类似,但是状态是组件私有的完全被组件自己控制的数据。

State 的基本使用

先来看看 State 的基本使用方式。目前我使用的是 16.6.0 版本的 React ,函数式组件中还不能支持 State ,但是未来版本中会支持的。

src/index.js

class App extends Component {
  render() {
    return <div>0</div>
  }
}

先到 src/index.js 中来添加一个普通的类组件。这里显示了0,如果0只是作为一个字符串显示,那么就没有必要抽出成 State ,但是对于一些会发生变化的内容,就要抽出成 State 。

class App extends Component {
  state = {
    count: 0
  }

  render() {
    return <div>{this.state.count}</div>
  }
}

具体方式就是,定义一个名为 state 的对象,里面的每个属性就是一个 state 了。例如,这里有了一个 state 叫做 count ,对应的值是0。下方 JSX 中,用 this.state.count 就可以得到 state 值了。

这就是 state 使用的基本方式。

如何更新 State

如果 state 数据不更新,就看不出 state 有什么意义。下面来看看如何更新 state 。

  handleClick = () => {
    console.log('Clicked!')
  }

  render() {
    return (
      <div>
        {this.state.count}
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }

这里我们需要在组件中添加一个按钮,点击按钮触发一个 event ,关于 event ,这里我们不展开。如果要响应点击事件就用 onClick 指定一个事件处理函数即可,这里的函数名叫做 handleClick。定义 handleClick ,里面打印一条信息。浏览器中可以看到信息打印出来了,表示事件处理函数运行良好。

更新 state 时要特别注意,不允许直接赋值修改。

  handleClick = () => {
    console.log('Clicked!')
    this.state.count = 1
  }

这种写法是错误的。

正确的方式是使用 setState 来更新状态值。

  handleClick = () => {
    console.log('Clicked!')
    this.setState({
      count: 1
    })
  }

这样,浏览器中再点一下按钮,state 值就更新为1了。至于为何有这个规定,咱们这里不深究,简单来讲 ,React 坚持函数式编程思想,而保持变量不变性是函数式编程的基本原则。

除了不可直接修改 state 值,另外一个要特别注意的问题是,setState 是个异步函数,这就造成不能直接根据上一个 state 值来生成下一下 state 值。比如我们想让每次点按钮的时候 count 都加一。

// Wrong
this.setState({
  count: this.state.count + 1 
});

直观的想法就是写成这样。但是由于 setState 是异步的,也就是说,第二次触发 setState 的时候,第一次未必已经执行完毕,所以直接用上次的 state 去更新这次的 state ,是不可靠的。

// Correct
this.setState((state, props) => ({
  count: state.count + 1
}))

好在 setState 有专门的一种写法去应对这种情况,传递给 setState 一个回调函数,其中第一个参数 state 就可以放心的作为上一次 state 来使用了。

关于如何更新 state ,就聊这么多。

状态和属性的区分

初学者遇到的另外一个困难是不太容易区分 state 和 props ,所以本节最后一部分,聊聊二者的区别。关键把握一句话:props 是组件和外界联通的桥梁,state 是组件私有的。

我们先来理解一下前半句:props 是组件和外界沟通的桥梁。

class Box extends Component {
  render() {
    return (
      <h3>
        父组件计数值
        {this.props.num}
      </h3>
    )
  }
}

   <Box num={this.state.count} />

例如,给 App 组件添加一个子组件 Box ,显示 App 组件的 count 值,这个时候,就可以给 Box 设置一个 props 值叫做 num ,传递 count 给它,这样 App 的数据就可以传入 Box 组件中显示了。所以说 props 是组件连接外部的桥梁。

那么下半句“state 是组件私有”的,如何理解呢?首先说,当前组件的 state 不能直接在其他组件中使用,包括它的子组件。另外,当前组件的 state 值也不能在其他组件中去直接修改,这种限制形成了对组件的良好封装,保证了代码的逻辑简单。

关于 props 和 state 的区别,咱们就先聊到这里。

总结

这节关于组件状态,也就是 state ,就聊这么多。需要记住的是:首先, state 值是在组件中,通过定义 state 对象来设置初始值的,第二,state 值是不能直接修改的,而要使用 setState 来更新,第三,props 是组件跟外界沟通的桥梁,而 state 是组件私有的数据。