React组件的数据

React组件的数据分两种,prop和state,prop或state的改变都会引发组件的重新渲染。prop是组件的对外接口,state是组件的内部状态,对外用prop,对内用state。

React的prop

当外部世界要传递数据给React组件,最直接的方式就是通过prop;同样,React组件要反馈数据给外部,也可以通过prop。prop的类型不限于纯数据,也可以是函数,函数类型的prop等于父组件传递给子组件一个回调函数,子组件可以对这个回调函数传参,这样就可以把信息传给外部世界。

// ./lesson2/chapter1/ControlPanel.js

class ControlPanel extends Component {
    constructor() {
        super(...arguments);
        this.handleClick = this.handleClick.bind(this);
    }
    handleClick(name) {
        alert(name)
    }
    render() {
        console.log('enter ControlPanel render');
        return (
            <div style={style}>
                <Counter caption="First" handleClick={this.handleClick}/>
            </div>
        );
    }
}
//  ./lesson2/chapter1/Counter.js

class Counter extends Component {
    constructor(props) {
      super(props);
      this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
        this.props.handleClick('点我啊');
    }
    render() {
        const {caption} = this.props;   //  ES6对象结构的写法
        return (
            <div>
                <button onClick={this.handleClick}>+</button>
                <span>caption:{caption}</span>
            </div>
        );
    }
}

读取prop值

从上面例子可以看到ControlPanel.js中组件Counter传递一个叫作caption的prop,其值为First,又传递了一个叫作handleClick的prop,其值是一个函数。在Counter.js中,通过this.props.caption即可获得caption的值。在Counter组件中,我们给一个button绑定点击事件,调用从父组件传递过来的handleClick函数,并传递一个参数给父组件。

先回顾一下,在ES6的课程中,关于CLASS的super我们说过以下几点:

  • super()方法可访问基类的构造函数
  • super()只可在派生类的构造函数中调用
  • super()负责初始化this,在构造函数中访问this前要调用super()

在Counter组件中,我们可以看到:一个组件需要定义自己的构造函数,需要在第一行调用super(props) [constructor中可能还会传入其他参数,也可这样写super(...arguments)];给super()传入props作为参数,则可在构造函数中访问this.props。在构造函数中还给成员函数绑定了当前this的执行环境,ES6方法创造的React组件类并不会自动给我们绑定this到当前对象。

propTypes检查

既然prop是组件的对外接口,那么就应该有某种方式让组件申明自己的接口规范。ES6定义的组件类中,可以通过增加类的propTypes属性来定义prop规格。

比如,对Counter组件的propTypes定义如下代码:

Counter.propTypes = {
    caption: PropTypes.string.isRequired,
    initValue: PropTypes.number
}

其中要求caption必须是string类型,initValue必须是number,并且caption的值还是必须存在的。为了验证,可将ControlPanel.js中的render函数增加如下代码

<Counter caption={123}/>

控制台中可以看到一个红色的提示警告。

propTypes虽然能够在开发阶段发现代码问题,但在产品环境中并不需要。因为propTypes检查也是要消耗CPU计算资源的。所以最好的方式是,开发环境定义propTypes,生产环境通过babel-react-optimize优化去掉propTypes。关于propTypes具体用法请参见官方文档

React中的state

驱动组件渲染过程的除了prop,还有state,state代表组件的内部状态。由于React不能修改传入的prop,所以只能通过修改state来记录自身数据的变化。

// ./lesson2/chapter2/Counter.js
class Counter extends Component {
    constructor(props) {
        ... ...
        this.state = {
            count: props.initValue
        }
    }

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

    onClickDecrementButton() {
        this.setState({count: this.state.count - 1});
    }

    render() {
        const {caption} = this.props;
        return (
            <div>
                <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
                <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
                <span>{caption} count: {this.state.count}</span>
            </div>
        );
    }
}

Counter.defaultProps = {
    initValue: 0
};

export default Counter;

初始化state

在Counter组件中,我们通过this.state完成对组件state的初始化,代码如下:

constructor(props) {
    ... ...
    this.state = {
        count: props.initValue || 0
    }
}

组件的state必须是一个javascript对象。通常情况,我们不会通过state设置初始值,而是通过React的defaultProps的功能。

constructor(props) {
    ... ...
    this.state = {
        count: props.initValue
    }
}

Counter.defaultProps = {
    initValue: 0
};

读取和更新state

在button上绑定点击事件,通过触发点击的回调函数来改变state值。代码如下:

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


<button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>

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

prop和state的对比

  • prop用于定义外部接口,state用于记录内部状态
  • prop的值通过外部组件传入,state的值在组件内部定义
  • 组件不应该修改prop的值,state存在的目的就是让组件来改变的
原文地址:https://www.cnblogs.com/renzhiwei2017/p/9439242.html