公众号:程序员波波
开发中可能会用到一些第三方的组件或者是早期开发的组件,而这些组件并不受控。就是说组件内部维护了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