使用 react 的 hooks 进行全局的状态管理

使用 react 的 hooks 进行全局的状态管理

React 最新正式版已经支持了 Hooks API,先快速过一下新的 API 和大概的用法。

// useState,简单粗暴,setState可以直接修改整个state
const [state,setState] = useState(value);
 
// useEffect,支持生命周期
useEffect(()=>{
    // sub
    return ()=>{
        // unsub
    }
},[]);
 
// useContext,和 React.createConext() 配合使用。
// 父组件使用 Context.Provider 生产数据,子组件使用 useContext() 获取数据。
const state = useContext(myContext);
 
// useReducer,具体用法和redux类似,使用dispatch(action)修改数据。
// reducer中处理数据并返回新的state
const [state,dispatch] = useReducer(reducer,initialState);
 
// useCallback,返回一个memoized函数,第二个参数类似useEffect,只有参数变化时才会更改。
const memoizedCallback = useCallback(
  () => {
    doSomething(a,b);
  },[a,b],);
 
// useMemo,返回一个memoized值,只有第二个参数发生变化时才会重新计算。类似 useCallback。
// useCallback(fn,inputs) 等效 useMemo(() => fn,inputs)。
const memoizedValue = useMemo(() => computeExpensiveValue(a,b),b])
 
// useRef,返回一个可变的ref对象
const refContainer = useRef(initialValue);
// useImperativeMethods,详情自行查阅文档
// useMutationEffect,类似useEffect,详情自行查阅文档
// useLayoutEffect,类似useEffect,详情自行查阅文档

  

 

一开始以为使用 useState 分离数据层 和 UI 层,就可以达到数据共享了,后来发现想的太简单了。分离只是逻辑共享,数据都是独立的。

后来发现有个 useReducer  似乎和 redux 很像,然而本质上,还是 useState 实现的。

再继续探索发现,基于useContext,同时配合useReducer一起使用。

但是,这个方案的缺陷是,当数据太大,组件太多,会直接导致渲染性能下降。

每一次state的变化,都会从顶层组件传递下去,性能影响比较大。

当然也有一些优化手段,比如使用memo()或者useMemo(),又或者拆分更细粒度的context,对应不同的数据模块,再包装成不同的ContextProvider,只是这样略显繁琐了。

后面,终于找到一位大神的作品,经过简单的修改后得出一个可以使用的办法:

import { useState,useEffect  } from ‘react‘;

const isFunction = fn => typeof fn === ‘function‘;
const isObject = o => typeof o === ‘object‘;
const isPromise = fn => {
  if (fn instanceof Promise) return true;
  return isObject(fn) && isFunction(fn.then);
};
// Model 类
class Model {
  constructor({initialState,actions}){
      this.state = initialState;
      this.actions = {};
      this.queue = [];
      Object.keys(actions).forEach((name)=>{
          this.actions[name] = (arg)=>{
              const res = actions[name].call(this,this.state,arg);
              if(isPromise(res)){
                Promise.resolve(res).then((ret)=>{
                  this.state = ret;
                  this.onDataChange();
                });
              }else{
                this.state = res;
                this.onDataChange();
              }
          }
      });
  }
  useStore(){
    const [,setState] = useState();
      // 使用useEffect实现发布订阅
    useEffect(() => {
      const index = this.queue.length;
      this.queue.push(setState); // 订阅
      return () => { // 组件销毁时取消
        this.queue.splice(index,1);
      };
    },[]);
    return [this.state,this.actions];
  }
  onDataChange(){
      const queues = [].concat(this.queue);
      queues.forEach((setState)=>{
          setState(this.state); // 通知所有的组件数据变化
      });
  }
}




// models/user.js

const sleep = async t => new Promise(resolve => setTimeout(resolve,t));
const initialState = {};
const actions = {
    async setUserInfo(){
        await sleep(2000);
        return Promise.resolve({name:"mannymu",age:18});
    },setAge(state,age){
        return Object.assign({},{...state,age});
    },setName(state,name){
        return Object.assign({},name});
    },loginOut(){
      return null;
    }
}

const user = new Model({
    initialState,actions
});



// 组件
import {useStore} from ‘../models/user‘;
const Person = ()=>{
    const [state,actions] = useStore();
    return (
        <div>
            <span> My name is {state.name}.</span>
            <button onClick={()=> actions.setName(‘han meimei.‘)}>btn1</button>
        </div>
    )
};

  

 

这样就可以使用简单的代码,管理复杂的状态了。同时支持异步。

参考文档:https://blog.csdn.net/tzllxya/article/details/92798097

参考github: https://github.com/yisbug/iostore

 

通过查看那位大佬在 github 上面的完整版状态管理插件源码。其基于上面的代码基本原理。做了 Proxy 的封装,就可以像  vue 一样,直接修改 this.xxx 来更新视图层。

 

 

最后,附上我的本地文件夹分类:

分享图片

 

 

其中 store.js 里面,是上面的 Model 类。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom