在看Vue.js文档的时候,看到深入响应式原理这一节时,顺便想了想如何模仿Vue.js的双向绑定原理来实现react的双向绑定。
Vue.js的双向绑定中,使用Object.defineProperty来设置属性的setter和getter,从而把属性变为一个observable。于是,是不是也可以使用相同的方法来实现react的绑定呢。
首先,react中改变state需要使用setState来实现:
setState({
name: "value"
})
我们可以通过Object.defineProperty来改变name属性的setter
Object.defineProperty(this.state, "name", {
set: newName => {
this.setState({
name: newName
})
}
})
通过设置之后,我们应该就可以在组件中直接使用
this.state.name = "new Name"
通过上面的思考,为了进一步简化双向绑定的步骤,我们可以写出一个双向绑定的工具函数:
function defineObservableState(this, mState) {
if (!this.state) this.state = {}
Object.keys(mState).forEach(key => {
Object.defineProperty(this.state, key, {
value: mState[key],
set: newName => {
this.setState({
name: newName
})
}
})
})
}
这样,我们就可以直接使用
class Home extends React.Component {
constructor(props) {
super(props)
defineObservableState(this, {
name: "my name"
})
}
}
需要注意的是,此时给name赋值,state的改变是异步的。
那么,表单如何绑定变量呢
<input type="text" valueLink={{ value: this.state.name, requestChange: newValue => this.state.name = newValue }} />
从代码中我们看到,valueLink略显冗余,我们来对input进行一层包装
props => (
<input valueLink={{ value: props.bindValue, requestChange: newValue => props.bindValue = newValue }} ...props />
)
这样就基本实现了react双向绑定的功能。
作为学习中的记录,代码中或许有些不足,欢迎交流