TSyringe는 의존성 주입(Dependency Injection)을 위한 라이브러리이다.
📍 의존성 주입(Dependency Injection)
여러 컴포넌트가 있을 때, 하나의 컴포넌트가 다른 컴포넌트의 기능을 사용하거나 참조할 때, 의존성이 생긴다.
의존성 주입은 이런 의존성을 느슨하게 만들어주는 디자인 패턴이다.
// store/Store.ts
import 'reflect-metadata';
@singleton()
export default class Store {
count = 0;
listeners = new set();
update() {
this.listeners.forEach((listeners) => {
listeners();
})
}
addListener(listener) {
this.listeners.add(listener);
}
removeListener(listener) {
this.listeners.delete(listener);
}
}
// component/CountControl.tsx
import { container } from "tsyringe";
import Store from "../store/Store";
export default function CountControl() {
const store = container.resolve(Store);
const handleClickIncrease = () => {
store.count += 1;
store.publish();
}
const handleClickDecrease = () => {
store.count -= 1;
store.publish();
}
return (
<div>
<button onClick={handleClickIncrease}>
Increase
</button>
<button onClick={handleClickDecrease}>
Decrease
</button>
</div>
)
}
// component/Counter.tsx
import { container } from "tsyringe";
import Store from "../store/Store";
export default function Counter() {
const store = container.resolve(Store);
// 강제 리랜더링 해주는 함수
const forceUpdate = useForceUpdate();
store.forceUpdates.add(forceUpdate);
useEffect(() => {
store.addListener(forceUpdate);
return () => {
store.removeListener(forceUpdate);
}
}, [store, forceUpdate])
return (
<div>
<p>{store.count}</p>
</div>
)
}
// App.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
const context = describe;
describe('APP', () => {
beforeEach(() => {
container.clearInstances();
})
context('when press increase button once', () => {
test('counter', () => {
render(<APP />);
fireEvent.click(screen.getByText('Increase'));
const elements = screen.getAllByText('1');
expect(elements).toHaveLength(1);
})
})
})
싱글톤 패턴은 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고,
최고 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.