乐趣区

关于前端:helux一个鼓励服务注入的响应式react状态库

对于 helux

helux 是一个激励服务注入,并反对响应式变更 react 的全新数据流计划,它的前身是 concent(一个类 vue 开发体验的高性能状态治理框架),但 concent 本身因为须要兼容 class 和 function 保持一致的语法,且为了对其 setup 性能,导致外部代码量切实太大,压缩后有 70 多 kb,api 裸露得也十分多,导致学习难度急剧回升,为了更合乎当初十分风行的 DDD 围绕业务概念构建畛域模型的编码趋势,helux一开始就设计为 激励服务注入 反对响应式变更 反对依赖收集 的轻量级 react 数据流计划。

它领有以下劣势:

  • 轻量,压缩后 2kb
  • 简略,仅裸露 6 个 api
  • 高性能,自带依赖收集
  • 响应式,反对创立响应式对象,在视图之外变更对象将同步更新视图
  • 服务注入,配合 useService 接口轻松管制简单业务逻辑
  • 状态晋升 0 改变,所以中央仅需将 useObject 换为 useSharedObject 即可晋升状态共享到其余组件
  • 防止 forwordRef 天堂,内置的 exposeService 模式将轻松解决父掉子时的 ref 转发艰涩了解问题和传染性(隔代组件须要层层转发)
  • ts 敌对,100% ts 编写,为你提供全方位类型提醒

为什么起名 helux,尽管心田上我是把它作为concent v3 版本去开发的,但因为它的变动切实太大,除了依赖收集不继承任何concent 的个性,同时它也是随同我开发的 hel-micro 诞生一款作品,我冀望它成为 hel-micro 生态的 luxury 级别的奉献,就将 hel-micro 和 luxury 两个词拼一起成为了 helux

欢送点星关注 helux,它尽管较新,但已在我本人的应用场景中施展功不可没的作用,现已退出 hel-micro 生态大仓,期待能成为你违心筛选的一款可心数据流计划。

疾速上手

极致的简略是 helux 最大的劣势,理解以下 6 个 api 后,你能够轻松应酬任何简单场景,最大的魅力在于 useSharedObjectuseService两个接口,且看如下 api 介绍

以下所有 api 均对应有在线示例 1 和示例 2, 欢送 fork 并批改体验。

useObject

应用 useObject 有两个益处

  • 1 不便定义多个状态值时,少写很多 useState
  • 2 外部做了 unmount 判断,让异步函数也能够平安的调用 setState,防止 react 呈现正告 :
    “Called SetState() on an Unmounted Component” Errors
// 基于对象初始化一个视图状态
const [state, setState] = useObject({a:1});
// 基于函数初始化一个视图状态
const [state, setState] = useObject(()=>({a:1}));

useForceUpdate

强制更新以后组件视图,某些非凡的场景能够应用它来做视图重刷新

const forUpdate = useForceUpdate();

createSharedObject

创立一个共享对象,可透传给 useSharedObject,具体应用见 useSharedObject

// 初始化一个共享对象
const sharedObj = createSharedObject({a:1, b:2});
// 基于函数初始化一个共享对象
const sharedObj = createSharedObject(()=>({a:1, b:2}));

createReactiveSharedObject

创立一个响应式的共享对象,可透传给 useSharedObject

// 初始化一个共享对象
const [reactiveObj, setState] = createReactiveSharedObject({a:1, b:2});

sharedObj.a = 111; // 任意中央批改 a 属性,触发视图渲染
setSharedObj({a: 111}); // 应用此办法批改 a 属性,同样也能触发视图渲染,深层次的数据批改可应用此办法

useSharedObject

函数签名

function useSharedObject<T extends Dict = Dict>(sharedObject: T, enableReactive?: boolean): [
  SharedObject<T>,
  (partialState: Partial<T>) => void,
]

接管一个共享对象,多个视图里将共享此对象,外部有依赖收集机制,不依赖到的数据变更将不会影响以后组件更新

const [obj, setObj] = useSharedObject(sharedObj);

useSharedObject默认返回非响应式状态,如须要应用响应式状态,透传第二位参数为 true 即可

const [obj, setObj] = useSharedObject(sharedObj);
// now obj is reactive
 setInterval(()=>{state.a = Date.now(); // 触发视图更新
 }, 2000);

useService

函数签名

/**
 * 应用用服务模式开发 react 组件:* @param compCtx
 * @param serviceImpl
 */
function useService<P extends Dict = Dict, S extends Dict = Dict, T extends Dict = Dict>(
  compCtx: {
    props: P;
    state: S;
    setState: (partialState: Partial<S>) => void;
  },
  serviceImpl: T,
): T & {
  ctx: {setState: (partialState: Partial<S>) => void;
    getState: () => S;
    getProps: () => P;};
}

它可搭配 useObjectuseSharedObject一起应用,会创立服务对象并返回,该服务对象是一个稳固的援用,且它蕴含的所有办法也是稳固的援用,可平安办法交给其它组件且不会破会组件的 pros 比拟规定,防止懊恼的 useMemouseCallback脱漏相干依赖

搭配 useObject

function DemoUseService(props: any) {const [state, setState] = useObject({a: 100, b: 2);
  // srv 自身和它蕴含的办法是一个稳固的援用,// 可平安的将 srv.change 办法交给其它组件且不会破会组件的 pros 比拟规定
  const srv = useService({props, state, setState}, {change(a: number) {srv.ctx.setState({ a});
    },
  });
  
  return <div>
    DemoUseService:
    <button onClick={() => srv.change(Date.now())}>change a</button>
  </div>;
}

搭配 useSharedObject 时,只需替换 useObject 即可,其余代码不必做任何扭转

+ const sharedObj = createSharedObject({a:100, b:2})

function DemoUseService(props: any) {-  const [state, setState] = useObject({a: 100, b: 2);
+  const [state, setState] = useSharedObject(sharedObj);

getState 和 getProps

stateprops 是不稳固的,所以服务外部函数取的时候需从 srv.ctx.getStatesrv.ctx.getProps

// 形象服务函数
export function useChildService(compCtx: {
  props: IProps;
  state: S;
  setState: (partialState: Partial<S>) => void;
}) {
  const srv = useService<IProps, S>(compCtx, {change(label: string) {
      // !!! do not use compCtx.state or compCtx.state due to closure trap
      // console.log("expired state:", compCtx.state.label);

      // get latest state
      const state = srv.ctx.getState();
      console.log("the latest label in state:", state.label);
      // get latest props
      const props = srv.ctx.getProps();
      console.log("the latest props when calling change", props);

      // your logic
      compCtx.setState({label});
    }
  });
  return srv;
}

export function ChildComp(props: IProps) {const [state, setState] = useObject(initFn);
  const srv = useChildService({props, state, setState});
}

 return (
    <div>
      i am child <br />
      <button onClick={() => srv.change(`self:${Date.now()}`)}>
        change by myself
      </button>
      <h1>{state.label}</h1>;
    </div>
  );

exposeService

当孩子组件 props 上透传了 exposeService 函数时,useService 将主动透传服务对象给父亲组件,是一种比拟不便的逃离 forwardRef 实现父调子的模式

import {ChildSrv, Child} from "./Child";

function App() {
  // 保留孩子的服务
  const childSrv = React.useRef<{srv?: ChildSrv}>({});
  const seeState = () => {console.log("seeState", childSrv.current.srv?.ctx.getState());
  };

  return (
    <div>
      <button onClick={() => childSrv.current.srv?.change(`${Date.now()}`)}>
        call child logic
      </button>
      <Child
        unstableProp={`${Date.now()}`}
        exposeService={(srv) => (childSrv.current.srv = srv)}
      />
    </div>
  );
}

结语

helux是把 concent 外部精髓全副萃取提炼再加工后的全新作品,冀望能失去你的喜爱。❤️

退出移动版