useContext 需要注入基础信息与插入组件。
同层 state 共享又不在父组件通过 props 同步。遂尝试 hooks 同步方式。
大致思路:
- 使用闭包缓存
store信息 - 单纯调用
useState的setState方法触发组件更新
配置基础功能
const useBase = (store, actions = []) => {
const [, newChangeState] = useState();
useEffect(() => {
store.stateList.push(newChangeState);
return () => {
return (store.stateList = store.stateList.filter(
self => self !== newChangeState
));
};
}, [store]);
return [
store.state,
(() => {
const selfActions = {};
Object.keys(actions).forEach(funName => {
if (typeof actions[funName] === 'function') {
selfActions[funName] = actions[funName].bind(null, store);
}
});
return selfActions;
})(),
];
};
const useDefModule = (initState, actions) => {
const store = { state: initState, stateList: [] };
store.setState = newState => {
store.state = { ...store.state, ...newState };
store.stateList.forEach(fn => fn(store.state));
};
return useBase.bind(null, store, actions);
};
调用使用方式
const useModule = useDefModule.call(null, initState, {
changeState: ({ setState }) => {
setState({ value: Date.now() });
},
});
const Item1 = () => {
const [{ value }, { changeState }] = useModule();
return (
<div onClick={() => changeState({ value: Date.now() })}>123 {value}</div>
);
};
const Item2 = () => {
const [{ value }, { changeState }] = useModule();
useEffect(() => {
const id = setInterval(() => {
changeState({ value: Date.now() });
}, 1000);
return () => clearInterval(id);
}, [changeState]);
return (
<div onClick={() => changeState({ value: Date.now() })}>456 {value}</div>
);
};
export default () => {
const [show, changeShow] = useState(true);
return (
<>
<Item1 />
<button onClick={() => changeShow(!show)}>delete</button>
{show && <Item2 />}
</>
);
};
使用
bind、call纯粹为了屏蔽ESLint: React Hook "useDefModule" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function.(react-hooks/rules-of-hooks)