单向数据流只关注于在store中维护的唯一的state,消除了不必要的多种states带来的复杂度. 这个store应该具有能被我们订阅(subscribe)store中变化的能力,实现如下:
var Store = {
_handlers: [],
_flag: '',
onChange: function (handler) {
this._handlers.push(handler);
},
set: function (value) {
this._flag = value;
this._handlers.forEach(handler => handler())
},
get: function () {
return this._flag;
}
};
然后我们会在我们的App组件上加上订阅我们的store的钩子, 当每次store发生改变的时候, 我们的组件就会被重新的渲染.
class App extends React.Component {
constructor(props) {
super(props);
Store.onChange(this.forceUpdate.bind(this));
}
render() {
return (
<div>
<Switcher
value={ Store.get() }
onChange={ Store.set.bind(Store) }/>
</div>
);
}
}
请注意我们使用了forceUpdate这个函数,但是事实上我们并不推荐使用这个函数.
一般情况下我们会使用高阶组件去帮我们处理重新渲染的事情,我们在这里使用forceUpdate函数只是想尽可能的保持我们这个例子简单.
因为我们使用了store, Swticher这个组件就变得超级简单了. 我们不需要再在Switcher组件内部再去维护一份State了:
class Switcher extends React.Component {
constructor(props) {
super(props);
this._onButtonClick = e => {
this.props.onChange(!this.props.value);
}
}
render() {
return (
<button onClick={ this._onButtonClick }>
{ this.props.value ? 'lights on' : 'lights off' }
</button>
);
}
}
使用单向数据流的好处是我们的组件在这种情况下变得非常声明式, 成为了所谓的纯UI组件, 只是我们Store里面数据的表达. React在诞生之初就是为了解决视图层(View层)的问题, 其核心思想也是从视图出发去解决问题. 我们用声明式的方式去构建我们的应用, 让我们的组件变得尽可能的木偶化,只关心我们的数据,将我们的复杂的数据逻辑交由我们的store去处理. 这也是我们去构建React应用的时候的一种比较好的思路.