浅谈React受控与非受控组件

背景

React内部分别使用了props, state来区分组件的属性和状态。props用来定义组件外部传进来的属性, 属于那种通过外部定义以后, 组件内部就没法改变。而state维持组件内部的状态更新和变化, 组件渲染出来后响应用户的一些操做,更新组件的一些状态。若是组件内部状态不须要更新,即没有调用过this.setState, 所有经过props来渲染也是没问题的, 不过这种状况不常见。本文所介绍的内容就是经过props和state的定义来谈谈React的受控组件和非受控组件。react

非受控组件

顾名思义, 非受控组件即组件的状态改变不受控制.接来下咱们以一个简单input组件代码来描述。git

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class Demo1 extends Component {
    render() {
        return (
            <input />
        )
    }
}

ReactDOM.render(<Demo1/>, document.getElementById('content'))

在这个最简单的输入框组件里,咱们并无干涉input中的value展现,即用户输入的内容都会展现在上面。若是咱们经过props给组件设置一个初始默认值,<input defaultValue={this.props.value}/>defaultValue属性是React内部实现的一个属性,目的相似于input的placeholder属性。
ps: 此处若是使用value代替defaultValue,会发现输入框的值没法改变。github

受控组件

上面提到过,既然经过设置input的value属性, 没法改变输入框值,那么咱们把它和state结合在一块儿,再绑定onChange事件,实时更新value值就好了。redux

class Demo1 extends Component {
    constructor(props) {
        super(props);
        this.state = {
            value: props.value
        }
    }

    handleChange(e) {
        this.setState({
            value: e.target.value
        })
    }

    render() {
        return (
            <input value={this.state.value} onChange={e => this.handleChange(e)}/>
        )
    }
}

这就是最简单的受控组件模型, 咱们能够经过在onChange的回调里控制input要显示的值,例如咱们设置input框只能输入数字dom

this.setState({
    value: e.target.value.replace(/\D/g, '')
})

如今咱们应该彻底明白form表单中受控组件和非受控组件的关系。受控组件采起的理念相似于redux的单项数据流理念,即value值是在调用者上更新的。
那么问题来了。。。函数

最后的思考

如今咱们要实现一个简单的input的number类型组件,后面紧跟一个+的button按钮,将输入框内的数字每次加一。因此此处只能按照受控组件的理念来写this

import React, { Component } from 'react';

export default class extends Component {
    constructor(props) {
        super(props);
        this.state = {
            value: props.value
        }
    }

    handleChange(e) {
        this.setState({
            value: e.target.value.replace(/\D/g, '')
        })
    }

    plus() {
        const value = ++this.input.value
        this.setState({
            value,
        })
    }

    render() {
        return (
            <div>
                <input
                    value={this.state.value}
                    onChange={e => this.handleChange(e)}
                    ref={ref => this.input = ref}
                />
                <button onClick={() => this.plus()}>+</button>
            </div>
        )
    }
}

此处功能基本实现彻底,可是发现使用此组件以后,面临了另外一个问题,咱们如何在外部获取到这个输入框的值。一种方法是给组件增长个getValue回调的props,每次value值变化都调用一次getValue,即在handleChange和plus函数里调用,可是存在一个问题是,调用者只能经过getValue被动获取值,并且value值得改变此时仍是在组件内部自行变化,不符合受控组件原理,也不知足React单向数据流概念。另外一种方法就是将input组件的将要改变的值传到调用者里面,由调用者来决定更不更新组件的值,即此时数据由被调用者input组件生成,传至调用者,调用者判断知足条件后决定更新,再将数据从新传入到被调用者里。而调用者与被调用者彼此之间创建的联系方式经过input组件的props和调用者的state。此时input组件的代码以下code

export default class extends Component {
    constructor(props) {
        super(props);
        this.state = {
            value: props.value
        }
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            value: nextProps.value
        })
    }

    handleChange(e) {
        this.props.onChange(e.target.value)
    }

    plus() {
        const value = ++this.input.value
        this.props.onChange(value)
    }

    render() {
        return (
            <div>
                <input
                    value={this.state.value}
                    onChange={e => this.handleChange(e)}
                    ref={ref => this.input = ref}
                />
                <button onClick={() => this.plus()}>+</button>
            </div>
        )
    }
}

代码中的this.props.onChange就是调用者内部的函数,经过setState来更新input组件的value值。完整代码已放到github,欢迎指正交流。component

相关文章
相关标签/搜索