RReact学习笔记-组件的数据

组件的数据prop&state

引入

React组件的数据分为两种:prop和state,无论是prop还是state的改变都可能会引发组件的重新渲染,因此选择显得尤为重要。那么其实大体的原则也很简单,prop是组件对外的接口,state是组件内部的状态,即对外用prop对内用state。

prop

什么是prop

React中文文档官网的解释是:当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)转换为单个对象传递给组件,这个对象被称之为 “props”。但是,我总感觉这个有点拗口,prop就是从外部传递给组件的数据,一个React组件通过定义自己能够接受的prop就定义了自己的对外公共接口。组件之间通过prop来传递数据。

给prop赋值

例子:

1
2
3
4
<SampleButton 
id = "simple" borderWidth = {2} onClick = {onButtonClick}
style = {{color:"red"}}
/>

在上面的例子中,创建了名为SampleButton的组件实例,使用了名字分
别为id、border Width、onClick和style的prop,React组件的prop所能支持
的类型则丰富得多,除了字符串,可以是任何一种JavaScript语言支持的数
据类型。

注意:

当prop的类型不是字符串类
型时,在JSX中必须用花括号{}把prop值包住,所以style的值有两层花括
号,外层花括号代表是JSX的语法,内层的花括号代表这是一个对象常量。

当外部世界要传递一些数据给React组件,一个最直接的方式就是通过
prop;同样,React组件要反馈数据给外部世界,也可以用prop,因为prop的
类型不限于纯数据,也可以是函数,函数类型的prop等于让父组件交给了子
组件一个回调函数,子组件在恰当的实际调用函数类型的prop,可以带上必
要的参数,这样就可以反过来把信息传递给外部世界。

读取prop值

1
2
3
4
5
6
7
8
9
10

class Counter extends Component {
constructor(props) {
super(props);
}

this.state = {
count: props.initValue || 0
}
}
  • 子组件通过在构造函数中调用super(props),那么组件实例被构造之后,类实例的所有成员函数就可以通过this.props访问到父组件传递过来的props值。很明显,给this.props赋值是React.Component构造函数的工作之一。
  • 在构造函数中可以通过参数props获得传入prop值,在组件内部是通过其他函数中则可以通过this.props访问传入prop的值,
1
const {caption} = this.props;

props 不可变

props 一旦传入进来就不能改变。组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props。所有 React组件都必须像纯函数一样保护它们的 props 不被更改。

但是应用程序的 UI 是动态的,并会伴随着时间的推移而变化,那怎么ban?不急,有state。

state

State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。由于React组件不能修改传入的prop,所以需要记录自身数据变化,就要使用state。

初始化state

通常在组件类的构造函数结尾处初始化state,通过对this.state的赋值完成了对组件state的初始化

1
2
3
4
5
6
constructor(props) {
...
this.state = {
count: props.initValue || 0
}
}

组件的state必须是一个JavaScript对象,不能是string或者number这样的
简单数据类型,即使我们需要存储的只是一个数字类型的数据,也只能把它某个字段对应的值。

读取和更新state

通过this.state可以读取到组件的当前state。但是,改变组件state必须要使用this.setState函数,而不能直接去修改this.state。

直接修改this.state的值,虽然事实上改变了组件的内部状态,但只是野蛮地修改了state,却没有驱动组件进行重新渲染,既然组件没有重新渲染,当然不会反应this.state值的变化;而this.setState()函数所做的事情,首先是改变this.state的值,然后驱动组件经历更新过程,这样才有机会让this.state里新的值出现在界面。

this.setState()接受一个对象或者函数作为参数。

对象

传入一个对象的时候,这个对象表示该组件的新状态。但你只需要传入需要更新的部分就可以了,而不需要传入整个对象。

1
2
// Correct
this.setState({comment: 'Hello'});

函数

State 的更新可能是异步的

出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。当你调用 setState 的时候,React.js 并不会马上修改state。而是把这个对象放到一个更新队列里面,稍后才会从队列当中把新的状态提取出来合并到 state 当中,然后再触发组件更新

这里就自然地引出了 setState的第二种使用方式,可以接受一个函数作为参数。React.js 会把上一个 setState的结果传入这个函数,这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数,你就可以使用该结果进行运算、操作,然后返回一个对象作为更新 state 的对象:

1
2
3
4
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));

props VS state

  • props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props,否则组件的 props 永远保持不变。
  • state 的主要作用是用于组件保存、控制、修改自己的可变状态。state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState 方法进行更新,setState 会导致组件的重新渲染。

参考:【非常感谢!】

react官方中文文档

react.js小书

深入浅出React和Redux