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