开发中可能会用到一些第三方的组件或者是早期开发的组件,而这些组件并不受控。就是说组件内部维护了state或者内部修改了一下数据,导致组件的状态并不是由props来定义的。
所以我们希望通过封装一层,来使得组件变得受控。
步骤:
1、首先我们需要知道组件的状态是由哪些变量定义的。(比如富文本的状态是由富文本的内容定义的)
2、然后封装一层受控组件,受控组件通过props来控制组件。
3、受控组件需要区分两种行为。第一种是外部组件通过props的直接修改,来改变状态。第二种是内部组件自己修改状态,触发onChange来告诉外部组件修改props。第一种情况下,受控组件肯定需要手动改变组件的状态,来符合props。第二种情况下,其实是不需要更新组件的,因为组件已经是在onChange触发的状态下。
以富文本从不受控到受控为例:
有一个富文本组件RichEditor,它本身不受控,它内部维护了一个state。外部可以通过setData来改变状态,通过getData来获得状态。
那么封装一层RichEditorControl,它拥有一个last_data变量存储当前的状态。那么如果props中的data与last_data不等,需要通过setData改变富文本的状态,如果富文本内容主动修改了,那么需要更新last_data。这种情况下,在下一次componentDidUpdate的时候,last_data和props.data是相等的,并不会触发更新。
代码:
import React, { PureComponent } from 'react'; import RichEditor from './RichEditor'; class RichEditorControl extends PureComponent { constructor(props) { super(props) this.last_data = null this.onChange = this.onChange.bind(this) } onChange() { this.last_data = this.refs.richeditor.getData() if (this.props.onChange) { this.props.onChange(this.last_data) } } resetData() { const {data} = this.props if (data != this.last_data) { if (data) { this.refs.richeditor.setData(data) } this.last_data = data } } componentDidMount() { this.resetData() } componentDidUpdate() { this.resetData() } render() { const {data} = this.props return ( <RichEditor {...this.props} ref='richeditor' key={data ? 'notempty' : 'empty'} onChange={this.onChange} /> ) } } export default RichEditorControl