서비스 주입을 장려하는 반응형 반응 상태 라이브러리인 helux

헬럭스에 대하여

Helux 는 서비스 인젝션을 장려하고 반응형 변화를 지원하는 새로운 데이터 흐름 솔루션으로 그 전신은 concent (Vue와 같은 개발 경험을 가진 고성능 상태 관리 프레임워크)이지만, concent 자체가 클래스 및 기능과 호환되어야 유지 관리 가능 일관성 문법, 그리고 그 setup기능에 비해 내부 코드의 양이 너무 많습니다 압축 후 70많은 kb가 있고 API가 너무 많이 노출되어 학습 난이도가 급격히 증가합니다. 비즈니스 DDD개념을 중심으로 도메인 모델을 구축하는 매우 인기 있는 코딩 으로 helux처음부터 가벼운 반응 데이터 흐름 솔루션 으로 설계되었습니다 鼓励服务注入.支持响应式变更支持依赖收集

다음과 같은 장점이 있습니다.

  • 경량, 압축 후 2kb
  • 심플, 7 개 API만 노출, , createShared, useObject, 4개의 인터페이스만 자주 사용useSharedObjectuseService
  • 고성능 내장 의존성 컬렉션
  • 반응형, 반응형 개체 생성 지원, 뷰 외부의 개체 변경은 뷰를 동기식으로 업데이트합니다.
  • useService복잡한 비즈니스 로직을 쉽게 제어할 수 있는 인터페이스가 있는 서비스 주입은 항상 안정적인 참조를 반환하므로 useCallback종속성 성가심을 완전히 피할 수 있습니다.
  • 상태 프로모션 0이 변경되므로 다른 구성 요소와 공유할 프로모션 상태 useObject장소만 교체하면 됩니다.useSharedObject
  • forwordRef 지옥을 피하십시오. 기본 제공 exposeService모드는 부모가 자식을 삭제할 때 전달의 모호성과 전염 문제를 쉽게 해결할 것입니다 ref(세대 간격 구성 요소는 계층별로 전달되어야 함).
  • ts-친화적, 100% ts로 작성, 전반적인 유형 힌트 제공

3.gif

이 gif와 아래의 모든 API는 온라인 예제 1예제 2 에 해당합니다 . 경험을 분기하고 수정하는 데 오신 것을 환영합니다.

왜 이름을 붙였을까 , helux마음에 v3 버전으로 concent개발했지만 너무 많이 변해서 컬렉션에 의존하는 것 외에는 어떤 특징도 물려받지 않고, 내가 개발한 hel-micro 로 탄생한 작품 concent이기도 하다. hel-micro 생태계에 럭셔리 수준의 기여가 될 것으로 기대하여 hel-micro와 luxury라는 단어를 합성했습니다 .helux

helux 에 관심을 가져 주셔서 감사합니다 . 비교적 새롭지 만 이미 내 사용 시나리오에서 없어서는 안될 역할을했습니다. 이제 hel-micro 생태 dacang에 합류했습니다. 기꺼이 데이터 스트림이 될 수 있기를 바랍니다. 선택.계획.

빠르게 시작하기

궁극의 단순함이 helux의 가장 큰 장점입니다.아래의 6가지 API를 이해하시면 어떤 복잡한 장면도 쉽게 다룰 수 있습니다.가장 큰 매력은 두 가지 인터페이스에 있습니다.아래 API 소개를 보거나 온라인 예제 1 및 예제 useSharedObject2 useService포크 방문 하십시오 . 와서 경험하십시오.

useObject

useObject를 사용하면 두 가지 이점이 있습니다.

  • 1 여러 상태 값을 정의하는 것이 편리할 때 useState를 훨씬 적게 작성하십시오.
  • 2 내부적으로 마운트 해제 판단이 이루어지므로 비동기 함수도 setState를 안전하게 호출할 수 있으므로 "Called SetState() on an Unmounted Component" 오류에 대한 반응 경고를 피할 수 있습니다.
// 基于对象初始化一个视图状态
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 属性,同样也能触发视图渲染,深层次的数据修改可使用此方法
复制代码

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는 concent의 모든 내면의 본질을 추출하고 재가공한 새로운 작품 입니다 . 많은 관심과 격려 부탁드립니다. ❤️

추천

출처juejin.im/post/7222229682028462117