2-3-组件数据

今天我们要一起学习一下 React 组件当中对于数据的处理。

  • props
  • state
  • context

props

  • 传入变量
  • 传入函数
  • 传入组件
  • props.children

props其实就是属性Properties的缩写。

在形式上,props之于JSX就相当于attributes之于HTML。从写法上来看呢,我们为组件传入props就可以像为HTML标签添加属性一样:

JSX

HTML

在概念上,props对于组件就相当于JS中参数之于函数。我们可以抽象出这样一个函数来解释:

Component(props) = View

组件函数接受props作为参数最后返回视图内容。props比起原生HTML的属性要强大很多。HTML的属性只能传递某些固定的字符,props几乎可以传递所有的内容,包括变量、函数、甚至是组件本身。

props是只读的

在React中,props都是自上向下传递,从父组件传入子组件。并且props是只读的,我们不能在组件中直接修改props的内容。也即是说组件只能根据传入的props渲染界面,而不能在其内部对props进行修改。

props类型检查

正是因为props的强大,什么类型的内容都可以传递,所以在开发过程中,为了避免错误类型的内容传入,我们可以为props添加类型检查。

props默认值

由于props是只读的,我们不能直接为props赋值。React专门准备了一个方法定义props的默认值。

state

  • 初始化
  • setState方法
  • 向下传递数据

state如果要翻译的话可以翻译为状态。一个组件可以有状态,就像我们之前介绍过的有状态组件,也可以是整个React应用的状态。

在React中state也是我们进行数据交互的地方,又或者叫做state management状态管理。一个应用需要进行数据交互,比如同服务器之间的交互,同用户输入进行交互。话反过来,从API获取数据,处理用户输入也就是我们需要用到state的时候。

下面我们通过一些例子来说明state的用法以及一些需要特别注意的地方。

先看一个最简单的计数器例子,在新版本的React当中,我们通过类定义组件来声明一个有状态组件,之后在它的构造方法中初始化组件的state,我们可以先赋予它默认值。

之后就可以在组件中通过this.state来访问它,既然是state那么肯定涉及到数据的改变,因此我们还需额外定义一个负责处理state变化的函数,这样的函数中一般都会包含this.setState这个方法。

要注意到,和之前的props一样,初始化state之后,如果我们想改变它,是不可以直接对其赋值的,直接修改state的值没有任何意义,因为这样的操作脱离了React运行的逻辑,不会触发组件的重新渲染。所以需要this.setState这个方法,在改变state的同时,触发React内部的一系列函数,最后在页面上重新渲染出组件。

在 Codepen 上试试。

根据我们上面学习到的有关props和state的知识,我们再来一起看一个稍微复杂一些的示例:

在 Codepen 上试试。

同学们要注意到,在这个例子中,我依旧沿袭了上节课中展示组件和容器组件的概念。只要我们乐意,所有的React组件都可以拥有自己的state,但在实际的生产中,我们写出的90%的都是无状态组件。假如state分散在应用的各个组件当中,有的负责后端数据交互,有的负责处理用户输入,有的负责界面变换逻辑等等,后期维护起来是相当困难的。因此在开发React应用的过程中,我们应该尽量把state集中统一管理,通过props把state的数据传递到需要的组件当中。

比方说下面这个例子,在这个简易的货币汇率转换器中,3个组件,一个输入,两个输出都需要使用到同一个名为money的state,那么我们就需要为3个组件建立一个统一的父组件来管理他们公用的state,通过props将state中的值传递到子组件中,同样也可以将处理state的函数以props的方式传递下去,在子组件中触发父组件修改state的函数,以此来达到更改state重新渲染组件的目的。

随着我们开发应用的逐步扩展,它的state会变得越来越庞大复杂,假如分散到各个组件当中,对于日后应用的维护者来说将是一个噩梦。怎么处理怎么储存应用的state非常值得我们深入去思考,由此也就引发了一个问题——状态管理。这也正是我们学习过React之后,在下一个部分的教程中将要介绍的Redux专注解决的问题。

在 Codepen 上试试。

context

集中统一管理state也会引发另外一个问题,React当中的数据都是自上向下传递的,加入我们的state在最外层的一个组件中管理,但真正使用state中数据的组件可能在N层子组件的嵌套中,那么我们就需要在每层的子组件中都传递props下去,直至使用这个数据的子组件获取到为止,虽然可以让我们更清楚地看到数据流的传递和变化,但写起来真的非常痛苦。

React提供了一个名为context的实验性质的API来解决这一问题。我们直接来看这个对比props和context的例子:

在 Codepen 上试试。

通过props我们需要传递4层才能将数据传递到我们的目标组件中,而利用context的特性,只需要在最外层的应用组件中定义,直接在目标组件中使用即可。我们通过组件中的特殊方法getChildContext来定义context,另外要注意的是,必须用childContextTypes和contextTypes各自声明context的类型,否则我们无法获取context中的数据,只会返回一个空对象。

另外在小项目(比方说 Todo/货币汇率转换器/RSS阅读器 这类数据源单一好理解好控制的这类应用我们就叫它小项目)中,你可以试着把 state 玩溜,在初具规模的项目中我们还有一些更完整的解决方案,在以后的教程当中会介绍给同学们。

 

欢迎关注 余博伦 微信公众号