最近在使用 redux 做项目时,发现其 connect , reducer 等写法十分让人苦恼。给我们带来便利的同时产生了大量的模板代码。虽然一些大佬觉得其设计非常有逻辑且易维护,但其大量的模板代码及设计思路确实会让一些人心烦意乱。我思考了一下,有没有办法可以跳过 dispath 直接修改其值就能更新视图,以及不使用 connect 注入直接 import 导入状态使用。于是我便朝着这个方向去尽可能的实现一个 react 全局共享状态的方法。
首先全局共享即所有组件都可访问的数据,这个并不难。只需定义一个引用类型的数据,可以让其他组件访问到就行。例如:
const stateModel = {
count : 0
}
function App() {
return (
<div>
{stateModel.count}
</div>
);
}
接下来就是修改数据更新视图了。要监听到对象的数据变化我首先想到了 Proxy。我们创建一个函数 observe
。通过他实现数据的访问控制。
function observe(state){
return new Proxy(state,{
set(target,key,value){
// 组件即将更新
}
})
}
const stateModel = observe({
count : 0
})
接下来就是更新组件了,目前更新 react 组件的方法有 通过父级的传过来的 props (目前大部分 react 状态管理都是这种方式 )、或者通过 context 、react hook 函数、或者是 react 类组件的 component.forceUpdate() 方法。考虑到日前使用 react hook 组件的人占大多数(我本人也习惯使用 hook组件)。我想通过 react hook函数实现状态更新。版本1的 observe
函数来了。
function observe(state){
const [r,reflash] = useState(0);
return new Proxy(state,{
set(target,key,value){
state[key] = value;
reflash(r + 1);
return true;
}
})
}
带入到 App 组件测试
const stateModel = observe({
count : 0
})
function App() {
return (
<div>
{stateModel.count}
</div>
);
}
当我满怀期待的进行测试时,得到了 react 亲切的问候。
小丑竟是我自己,我忘记了 hook 函数必须在函数组件中才能被调用。所以我修改了策略。调用 observe
时返回一个包含 hook 函数的函数。
function observe(state){
return ()=>{
const [r,reflash] = useState(0);
return new Proxy(state,{
set(target,key,value){
state[key] = value;
reflash(r + 1);
return true;
}
})
}
}
再在 app 组件中执行。
const stateModel = observe({
count : 0
})
function App() {
const state = stateModel()
return (
<div>
{state.count}
<button onClick={()=>state.count++}>add count</button>
</div>
);
}
测试成功 !!!!。目前点击增加 count 没问题。那么是否就真的没问题了呢。看文章接下来的字数就知道没这么简单。我们尝试把 add 按钮单独放入一个组件。
function App() {
const state = stateModel()
return (
<div>
{state.count}
<AddBtn/>
</div>
);
}
const AddBtn = ()=>{
const state = stateModel()
return <button onClick={()=>state.count++}>add count</button>
}
测试你会发现,count 无法正常的增加。发生甚么事了,为什么何在一起可以分开就不行了呢。这是因为你每次调用 stateModel 就会返回不同的 new Proxy,App 组件的 state 和 AddBtn 组件的 state 看视一样实则完全是不同的两变量。AddBtn 中的 state 发生改变无法影响App 组件的 state。那么我们要让他们是同一个人。所以版本3诞生了。
const observe = (state)=>{
const reflashs;
const stateProxy = new Proxy(state,{
set(target,key,value){
state[key] = value;
const [r,reflash] = reflash;
reflash(r + 1);
return true;
}
})
return ()=>{
reflashs = useState(0)
return stateProxy
}
}
再次测试,发现 count 还是没有增加。再仔细看代码,直接对自己说句我是撒比。对呀之前的new Proxy 返回的不是同一个地址。这次 useState 返回的也不是同一个 hook 函数,这样他也无法更新其他组件。再次修改得到最终版本。
const observe = (state)=>{
const reflashMap = new Map();
const stateProxy = new Proxy(state,{
set(target,key,value){
state[key] = value;
for(const [r,reflash] of reflashMap.values()){
reflash(r+1);
}
return true;
}
})
return (key)=>{
reflashMap.set(key,useState(0))
return stateProxy
}
}
function App() {
const state = stateModel('App')
return (
<div>
{state.count}
<AddBtn/>
</div>
);
}
const AddBtn = ()=>{
const state = stateModel('AddBtn')
return <button onClick={()=>state.count++}>add count</button>
}
16行代码实现 observe 函数 react 全局状态共享。其中 reflashMap 用于存储每个组件的 key 及对应的渲染函数,这个 key 可以调用stateModel时传进来,每个组件拥有不同的 key。这篇文章我不仅讲了其实现原理,也讲了我实现的过程,只是希望大家也能多思考每一步代码究竟是怎么来的。 我沿着这个思路,再进行优化及添加了一些功能,开源了一个工具。 地址:https://www.npmjs.com/package/erwin
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!