DIContainer for react

곰튀김·2024년 6월 27일
0

아직도 미련을 못버렸네..

DIContainer.ts

export interface IDIContainer {
  regist: <T extends unknown>(name: string, builder: T | (() => T)) => void;
  resolve: <T extends unknown>(name: string) => T;
}

class DIContainer implements IDIContainer {
  private instances: Record<string, any> = {};

  regist = <T extends unknown>(
    name: string,
    instanceBuilder: T | (() => T)
  ): void => {
    this.instances[name] = instanceBuilder;
  };

  resolve = <T extends unknown>(name: string): T => {
    const instance = this.instances[name];
    if (!instance) throw new Error(`regist ${name} first`);
    if (typeof instance === "function") {
      const builder = instance as () => T;
      this.instances[name] = builder();
    }
    return this.instances[name] as T;
  };
}

const globalContainer: IDIContainer = new DIContainer();

export const getDIContainer = () => globalContainer;

DIContext.tsx

const DiContext = createContext<IDIContainer | null>(null);

export const DiProvider: FC<PropsWithChildren> = ({ children }) => {
  const container = useRef(getDIContainer());

  return (
    <DiContext.Provider value={container.current}>
      {children}
    </DiContext.Provider>
  );
};

export const useDiContainer = () => {
  return useContext(DiContext)!;
};

export const useDIContainerInstance = <T extends unknown>(name: string): T => {
  const container = useContext(DiContext)!;
  const instance = useRef<T>(container.resolve<T>(name));
  return instance.current;
};
profile
사실주의 프로그래머

0개의 댓글