likes
comments
collection
share

一个船新的状态管理库,开启React开发新姿势。采用了发布订阅的设计模式,同时提供了大量React hooks,以一种新

作者站长头像
站长
· 阅读数 21

什么是状态管理库

状态管理库就是提供一种机制来集中管理和维护 React 应用中的状态,并且使得这些状态能够跨组件共享。

在2024年,已经有很多优秀的轮子可以使用,比如Redux,mobx,zustand等。

今天我来推荐的是一个鄙人自己写的一个船新的状态管理库:@extremelyjs/store

github地址:github.com/extremelyjs…

采用了发布订阅的设计模式,同时提供了大量React hooks,以一种新思路来管理状态,不再需要维护type和reducer,可以实现类似useState,setState式的使用方式。

同时具备了异步更新能力和持久化存储能力,同时采用ts开发,具备了完善的类型提示。

优势

  • 相比其他状态管理库,采用了类useState,setState的思想,更贴近React的开发。同时天然支持了良好的异步更新能力,持久化存储等能力。
  • 写法上更加自由,心智负担更小,同时可以结合异步请求,异步事件,loading订阅和值订阅。来进一步优化代码结构,建立起统一的代码规范。
  • 还支持了多种更新策略。

下载

npm i @extremelyjs/store

或者使用一个我提供的脚手架

npx @extremelyjs/cli

选择好配置之后快速创建一个项目

开始

环境要求

  • React Hooks版本
  • 如果需要本地持久化存储,需要在有localStorage的环境下使用(例如React native可以使用这个库,但是无法使用本地持久化能力)

订阅和更新数据

比如我们需要建立一个store,后续有一个更新组件可以使用他的更新能力,另一个组件可以使用他的订阅数据的能力。就可以建立一个如下的store.


// 创建num.ts这个store
import { createMapperHooksStore } from '@extremelyjs/store'

const numStore = createMapperHooksStore<number>(0)

export const useNum = numStore.useStoreValue // 监听state变化

export const setNum = numStore.setStoreValue // 修改state,支持value或者callback

export const resetNum = numStore.reset // 重置state

如过我们想订阅这个数据,就可以使用导出的use函数

const num = useNum();

直接在一个组件里面使用,就可以订阅后续所有的变化。

在更新的时候,我们也不必像其他的store库一样,关注和维护很多type,action等内容。而是可以直接像在React中使用useState,setState一样去set改变。就像React中的set会支持value或者回调,在该状态管理库中同样也支持传入value或者回调来使用。

例如我们可以在改变事件的组件中这样使用:


// 传入回调,在之前的基础上+1。
const handleClick = useCallback(
    () => {
      setNum(value => value + 1);
    },[]
 );

// 传入value,直接改变值。
const handleChangeValue = useCallback(
     () => {
        setNum(10);
     },[]
 );
    

或者在一些复杂的场景,我们可能喜欢封装好逻辑让其他开发者调用,也可以在内部封装好再导出,栗子如下:


import { createMapperHooksStore } from '@extremelyjs/store'

const numStore = createMapperHooksStore<number>(0)

export const useNum = numStore.useStoreValue // 监听state变化

export const setNum = numStore.setStoreValue // 修改state,支持value或者callback

// 封装一个简单的自增逻辑,正常这种不复杂的逻辑应该写到外面的,但是为了演示思想,那么这里就封装一个。
export const increment = () => setNum(n => n + 1);

export const resetNum = numStore.reset // 重置state

持久化

对于支持localStorage的环境,可以使用持久化能力。

我们传入第二对象参数withLocalStorage,并设置好key,即可使用持久化能力。

  const num = createMapperHooksStore<number>(0, {withLocalStorage: 'keyName'}) // keyName为自定义id

异步更新能力

请求订阅

对于异步更新,可以使用异步更新能力。比如一个纯粹的api的请求,我们已经明确了他的输入输出,便可以放入loadStoreValue来自动更新数据,或者订阅loading过程,无需额外的心智负担,同时也方便我们建立统一而优雅的开发规范。同时我们的ts也会在开发阶段做一些校验,对于参数/返回值与store中的值不符的情况,也可以及时发现并修改。

  import { createMapperHooksStore } from "@extremelyjs/store";
  // fetchCurrentPageContent是一个输出结果为string,入参为PageDataParams的一段fetch请求。
  import fetchCurrentPageContent from "../api/fetchCurrentPageContent";
  import { PageDataParams } from "../type/params";

  const pageDataStore = createMapperHooksStore<string,PageDataParams>('', { withLocalStorage: 'page-data-new' });

  export const usePageData = pageDataStore.useStoreValue; // 订阅state变化

  export const usePageDataLoading = pageDataStore.useStoreLoading; // 订阅Loding状态

  // 异步更新,支持传入参数
  export const loadPageData = pageDataStore.loadStoreValue(
      params => params,
      fetchCurrentPageContent
  );

异步事件的订阅

我们还提供了load的api来订阅异步任务。

function mockPromiseArray() {
    // 模拟十个异步任务,返回数字
    const arr: Promise<string>[] = []
    for (let i = 0; i < 10; i++) {
        arr.push(new Promise((resolve) => {
            setTimeout(() => resolve(String(i)), 1000 * i);
        }))
    }
    return arr;
}
// store文件
import { createMapperHooksStore } from "@extremelyjs/store/src/index";

const testAsyncStore = createMapperHooksStore<string>("",{strategy: "acceptSequenced"});

export const useTestAsync = testAsyncStore.useStoreValue;

export const loadTestAsync = testAsyncStore.load;

// react组件
const testAsync = useTestAsync();

同时我们还支持四种异步更新策略

你可以使用 strategy 配置异步策略,目前提供了四种异步策略:

策略描述
acceptFirst在多个异步任务同时发出的情况下,只接受第一个成功的结果。如果已经有成功的返回,则后续请求不再发出。
acceptLatest在多个异步任务同时发出的情况下,只接受最后一个发出的任务的结果,成功或失败。
acceptEvery在多个异步任务同时发出的情况下,接受所有的返回,按照到达的顺序处理。由于到达的顺序可能是乱序,你需要处理乱序导致的问题。
acceptSequenced在多个异步任务同时发出的情况下,按照任务发出的顺序,接受结果,当中间的任务到达时,则不再接受此任务之前发起的任务的结果,但依旧等待后续发出的结果。

默认使用 acceptSequenced 的策略,这个策略满足绝大多数情况,在你需要特别的优化的时候,你可以选择其他的策略。

直接取值

我们还提供了getStoreValuegetStoreLoading来直接取值。

Todo

  • 完善文档
  • 对于ReactNaitve,小程序的本地持久化支持
  • 更好的错误提示
  • 测试用例的完善
  • 异步策略的完善
转载自:https://juejin.cn/post/7408816726027337768
评论
请登录