helux, une bibliothèque d'états réactifs qui encourage l'injection de service

à propos de l'hélix

Helux est une nouvelle solution de flux de données qui encourage l'injection de services et prend en charge les changements réactifs. Son prédécesseur est le concent (un cadre de gestion d'état haute performance avec une expérience de développement de type Vue), mais le concent lui-même doit être compatible avec les classes et les fonctions à maintenir cohérence Grammaire, et pour sa setupfonction, la quantité de code interne est trop importante. Après compression, 70il y a beaucoup ko, et l'API est trop exposée, ce qui entraîne une forte augmentation de la difficulté d'apprentissage. Afin d'être plus en ligne avec le DDDcodage très populaire consistant à créer des modèles de domaine autour de concepts métier Trend, heluxconçu dès le départ comme une solution de flux de données réactive légère pour 鼓励服务注入, 支持响应式变更, .支持依赖收集

Il a les avantages suivants :

  • Léger, 2kb après compression
  • Simple, seules 7 API sont exposées, et seules createShared, useObject, useSharedObject, useService4 interfaces sont fréquemment utilisées
  • Collecte de dépendances intégrée hautes performances
  • Réactif, prend en charge la création d'objets réactifs, la modification d'objets en dehors de la vue mettra à jour la vue de manière synchrone
  • L'injection de service, avec useServicel'interface permettant de contrôler facilement la logique métier complexe, renvoie toujours des références stables, ce qui peut complètement éviter useCallbackles désagréments de dépendance
  • La promotion de statut 0 change, il suffit donc de useObjectremplacer le lieu par useSharedObjectle statut de promotion pour le partager avec d'autres composants
  • Évitez l'enfer de forwordRef, le mode intégré exposeServicerésoudra facilement refle problème d'obscurité et de contagion lors de la transmission lorsque le parent abandonne l'enfant (les composants d'intervalle de génération doivent être transmis couche par couche)
  • ts-friendly, 100% écrit en ts, vous fournissant des conseils de type complets

3.gif

Ce gif et toutes les API ci-dessous correspondent à l'exemple en ligne 1 et à l'exemple 2. Bienvenue pour bifurquer et modifier l'expérience.

Pourquoi est-il nommé , bien que je l' ai développé heluxen version v3 dans mon cœur , mais parce qu'il a trop changé, il n'hérite d'aucune fonctionnalité sauf en s'appuyant sur la collection, et c'est aussi un travail né avec le hel-micro que j'ai développé Je m'attends à ce qu'il s'agisse d'une contribution de niveau luxe à l'écologie hel-micro, alors j'ai réuni les mots hel-micro et luxe .concentconcenthelux

Bienvenue à prêter attention à helux . Bien qu'il soit relativement nouveau, il a déjà joué un rôle indispensable dans mes propres scénarios d'utilisation. Maintenant, il a rejoint le dacang écologique hel-micro. J'espère qu'il pourra devenir un flux de données que vous êtes prêt à choisir. planifier.

Démarrez rapidement

La simplicité ultime est le plus grand avantage de helux. Après avoir compris les 6 API suivantes, vous pouvez facilement gérer n'importe quelle scène complexe. Le plus grand charme réside dans les deux interfaces. Voir l'introduction de l'API ci-dessous, ou visitez l'exemple en ligne useSharedObject1 useServiceet l' exemple 2 fork et modifier Venez vivre l'expérience.

useObject

Il y a deux avantages à utiliser useObject

  • 1 Lorsqu'il est pratique de définir plusieurs valeurs d'état, écrivez beaucoup moins useState
  • 2 Un jugement de démontage est effectué en interne, de sorte que les fonctions asynchrones peuvent également appeler setState en toute sécurité, en évitant les avertissements en réaction : Erreurs "Called SetState() on an Unmounted Component"
// 基于对象初始化一个视图状态
const [state, setState] = useObject({a:1});
// 基于函数初始化一个视图状态
const [state, setState] = useObject(()=>({a:1}));
复制代码

useForceUpdate

Mettre à jour de force la vue actuelle du composant, qui peut être utilisée pour actualiser la vue dans certains scénarios spéciaux

const forUpdate = useForceUpdate();
复制代码

createSharedObject

Créez un objet partagé qui peut être transmis de manière transparente. useSharedObjectPour une utilisation spécifique, consultez useSharedObject

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

createReactiveSharedObject

Créer un objet partagé réactif qui peut être transmis de manière transparente à useSharedObject

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

sharedObj.a = 111; // 任意地方修改 a 属性,触发视图渲染
setSharedObj({a: 111}); // 使用此方法修改 a 属性,同样也能触发视图渲染,深层次的数据修改可使用此方法
复制代码

createShared

函数签名

function createShared<T extends Dict = Dict>(
  rawState: T | (() => T),
  enableReactive?: boolean,
): {
  state: SharedObject<T>;
  call: <A extends any[] = any[]>(
    srvFn: (ctx: { args: A; state: T; setState: (partialState: Partial<T>) => void }) => Promise<Partial<T>> | Partial<T> | void,
    ...args: A
  ) => void;
  setState: (partialState: Partial<T>) => void;
};
复制代码

创建响应式的共享对象,当需要调用脱离函数上下文的服务函数(即不需要感知props时),可使用该接口替代createSharedObjectcreateReactiveSharedObject,该接口的第二位参数为是否创建响应式状态,为 true 时效果同 createReactiveSharedObject 返回的 sharedObj

 const ret = createShared({ a: 100, b: 2 });
 const ret2 = createShared({ a: 100, b: 2 }, true); // 创建响应式状态
 // ret.state 可透传给 useSharedObject
 // ret.setState 可以直接修改状态
 // ret.call 可以调用服务函数,并透传上下文
复制代码

以下将举例两种具体的调用方式

// 调用服务函数第一种方式,直接调用定义的函数,配合 ret.setState 修改状态
function changeAv2(a: number, b: number) {
   ret.setState({ a, b });
}

// 第二种方式,使用 ret.call(srvFn, ...args) 调用定义在call函数参数第一位的服务函数
function changeA(a: number, b: number) {
   ret.call(async function (ctx) { // ctx 即是透传的调用上下文,
     // args:使用 call 调用函数时透传的参数列表,state:状态,setState:更新状态句柄
     // 此处可全部感知到具体的类型
     // const { args, state, setState } = ctx;
     return { a, b };
   }, a, b);
 }
复制代码

如需感知组件上下文,则需要useService接口去定义服务函数,可查看 useService 相关说明

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 est un tout nouveau travail après avoir extrait et retraité toute l'essence intérieure du contenu , dans l'espoir d'obtenir votre goût et vos encouragements. ❤️

Je suppose que tu aimes

Origine juejin.im/post/7222229682028462117
conseillé
Classement