Skip to content

Latest commit

 

History

History
158 lines (124 loc) · 3.9 KB

File metadata and controls

158 lines (124 loc) · 3.9 KB

TSyringe

TypeScript용 DI 도구(IoC Container)로써 External Store를 관리하는 데 활용할 수 있습니다.
React 컴포넌트 입장에서는 "전역"처럼 여겨지고 "Prop Drilling" 문제를 우아하게 해결할 수 있는 방법 중 하나입니다.

의존성 주입(Dependency Injection)

reflect-metadata는 Reflect API에 대한 polyfill 입니다. polyfill에는 여러 가지가 있지만 TSyringe에서는 reflect-metadata 사용을 권장합니다.

  • 의존성 설치
npm i tsyringe reflect-metadata
  • src/main.tsx 파일과 src/setupTests.ts 파일에서 reflect-metadata 임포트. reflect-metadata 임포트를 안했을때 발생하는 오류입니다. polyfill 에러
import 'reflect-metadata';
  • 싱글톤으로 관리할 CounterStore 클래스를 준비
import { singleton } from 'tsyringe';

@singleton()
class CounterStore {
	// …(중략)...
}
  • 에제 코드 CounterStore.ts
import { singleton } from "tsyringe";

type Listener = () => void;

// singleton이라는 건 전역에서 하나라는 뜻
@singleton()
export default class CounterStore {
  count = 0;

  listeners = new Set<Listener>()

  increase() {
    this.count += 1;
    this.public();
  }
  decrease() {
    this.count += 1;
    this.public();
  }

  public() {
    this.listeners.forEach((listener) => listener())
  }

  addListner(listener: Listener) {
    this.listeners.add(listener)
  }

  removeListner(listener: Listener) {
    this.listeners.delete(listener)
  }
}
  • 싱글톤 CounterStore 객체를 사용
import { container } from 'tsyringe';

const counterStore = container.resolve(CounterStore);
  • 예제 코드 useCounterStore.ts
  import { useEffect } from "react";
import { container } from "tsyringe";
import CounterStore from "../stores/CounterStore";
import useForceUpdate from "./useForceUpdate";

export default function useCounterStore() {
  const store = container.resolve(CounterStore)

  const forceUpdate = useForceUpdate();

  useEffect(() => {
    store.addListner(forceUpdate)
    return () => {
      store.removeListner(forceUpdate)
    }
  }, [store, forceUpdate])

  return store
}
  • 예제 코드 Counter.tsx
import useCounterStore from "../hooks/useCounterStore";

export default function Counter() {
  const store = useCounterStore()

  return (
    <>
    <div>
      <p>Count: {store.count}</p>
    </div>
    </>
  )
}
  • 예제코드 CountControl.tsx
import useCounterStore from "../hooks/useCounterStore";

export default function CountControl(){
  const store = useCounterStore();

  const handleClickIncrease = () => {
  store.increase()
  }
  const handleClickDecrease = () => {
  store.decrease()
  }

  return (
    <>
    <div>
      <p>{store.count}</p>
      <button type="button" onClick={handleClickIncrease}>Increase</button>
      <button type="button" onClick={handleClickDecrease}>Decrease</button>
    </div>
    </>
  )
}

tsconfig.json에서 아래 주석을 풀어줘야 에러를 해결할 수 있습니다.

"experimentalDecorators": true,
"emitDecoratorMetadata": true

decorators 에러

참고 자료