原理
在 动机 里的后半部分介绍了 Piex Store
出现的原因和 API 的构建过程,这里就详细的介绍一下其实现原理。
在 Demo1
中,去掉类型的代码如下:
export default function createStore(state, actions) {
let _state = state;
const _actions = actions;
let _setters = [];
async function dispatch(action) {
_state = await _actions[action.type](_state, action.payload);
_setters.forEach(setter => setter(_state));
}
function useStore() {
const [, setState] = useState(_state);
useEffect(() => {
_setters.push(setState);
return () => _setters = _setters.filter(setter => setter !== setState);
}, []);
return [_state, dispatch];
}
return { useStore, dispatch };
}
首先,createStore
会创建一个闭包,闭包里有 _state
、_actions
、_setters
三个变量。
useStore
是一个 自定义 hooks,会在组件里创建一个局部状态,初始状态就是闭包变量 _state
,同时会把 useState
返回值数组第二个参数 setState
存到 _setters
。并返回 _state
变量和 dispatch
方法。
_state
是一个引用类型,可以从中读取当前的状态数据。而 diaspatch
方法可以触发一个 action
,返回一个新的 state
,这里会把新的 state
赋值给 _state
,然后把 _setters
里面存储的 setState
调用一遍。
我们知道 Hooks 的 setState
方法被调用后会触发组件的更新,这里,每个用到 useStore
的组件的 setState
都会被触发,然后组件会更新,从 _state
中取到最新的状态数据,然后 render
呈现到界面上。
Demo2
的原理与 Demo1
一样,只是写法不同:
abstract class Store {
readonly state = {};
private setters = [];
public useStore = this._useStore.bind(this);
private _useStore() {
const [, setState] = useState(_state);
useEffect(() => {
this.setters.push(setState);
return () => this.setters = this.setters.filter(setter => setter !== setState);
}, []);
return [_state, dispatch];
}
public setState(updater) {
this.state = Object.assign({}, this.state, nextState);
this.setters.forEach(setter => setter(this.state));
}
}
Demo2 中由 createStore
的闭包变成了 Store
对象,_state
变成了 this.state
,_setters
变成了 this.setters
,useStore
从一个函数变成了 Store
对象的方法,dispatch
变成了 setState
,只是 API 和表现形式上变了,内在逻辑还是一样的。
useStore
是一个自定义 Hooks,生成 setState
存到 this.setters
,每次 setState
会生成一个新的 state
,触发所有的组件更新。
Piex Store 的原理就是如此简单,自定义 Hooks 的更新机制实现起来不到二十行代码,却大有可为。