2. TSyringe
TSyringe๋?
TSyringe ๋ ๊ฐ๋ฒผ์ด DI ์ปจํ ์ด๋์ด๋ค.
TypeScript์ฉ DI๋๊ตฌ(IoC Container(์ ์ด์ ์ญ์ ))์ด๋ฉฐ, External Store๋ฅผ ๊ด๋ฆฌํ๋๋ฐ ํ์ฉ ๊ฐ๋ฅ ํ๋ค. React์์ ๋ฌธ์ ๊ฐ ๋๋ Prop Driling ๋ฌธ์ ๋ฅผ ์ฐ์ํ๊ฒ ํด๊ฒฐํ ์ ์๋ค.
DI๋?(Dependency Injection - ์์กด์ฑ ์ฃผ์
)
์ํํธ์จ์ด ๊ณตํ์์ ์ค์ํ ๊ฐ๋ ์ค ํ๋๋ก, ํด๋์ค๋ ๋ชจ๋์ด ํ์๋ก ํ๋ ์์กด์ฑ์ ์ง์ ์์ฑํ๊ฑฐ๋ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์๋๋ผ ์ธ๋ถ์์ ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋ ๋ฐฉ์์ ์๋ฏธํ๋ค.
์๋ฅผ ๋ค์ด ์๋น์ค ํด๋์ค๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ธ์ค ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ ๋, ์๋น์ค ํด๋์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ธ์ค ๊ฐ์ฒด์ ์์กดํ๊ณ ์๋ค.
DI๋ ์ด๋ฌํ ์์กด์ฑ์ ์ธ๋ถ์์ ์ฃผ์ ๋ฐ๋๋ก ์ค๊ณํจ์ผ๋ก์จ, ์ฝ๋์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ์์ง๋ ฅ์ ๋์ธ๋ค.
Coupling(๊ฒฐํฉ๋)
๋ ๋ชจ๋ ๊ฐ์ ์ํธ ์์กด์ฑ.
๊ฒฐํฉ๋๊ฐ ๋ฎ์์๋ก ๋ชจ๋ ๊ฐ์ ์์กด์ฑ์ด ์ ์ด์ ธ ๋ชจ๋์ ๋ณ๊ฒฝ์ด ๋ค๋ฅธ ๋ชจ๋์ ๋ฏธ์น๋ ์ํฅ์ด ์ค์ด๋ฌ.
๊ฒฐํฉ๋๊ฐ ๋์ผ๋ฉด ๋ชจ๋ ๊ฐ์ ์์กด์ฑ์ด ๊ฐํด์ ธ, ํ๋์ ๋ชจ๋์ ๋ณ๊ฒฝํ ๋ ๋ค๋ฅธ ๋ชจ๋์ ์ํฅ์ ๋ฏธ์น ๊ฐ๋ฅ์ฑ์ด ๋์์ง
Cohesion(์์ง๋ ฅ)
๋ชจ๋ ๋ด๋ถ์ ์์๋ค์ด ์๋ก ๊ด๋ จ๋ ๊ธฐ๋ฅ์ ์ํํ๋ ์ ๋.
๋์ ์์ง๋ ฅ์ ํ ๋ชจ๋์ด ํ๋์ ๊ธฐ๋ฅ์ ์ง์ค๋์ด์๊ณ , ๋ค๋ฅธ ๊ธฐ๋ฅ๊ณผ๋ ๋ ๋ฆฝ์ ์ผ๋ก ๋์.
๋ฎ์ ์์ง๋ ฅ์ ๋ชจ๋ ๋ด์ ์์๋ค์ด ์๋ก ๋ค๋ฅธ ๋ชฉ์ ์ ์ํด ํผํฉ๋์ด ์๊ฑฐ๋, ๊ด๋ จ์๋ ๊ธฐ๋ฅ์ ์ํํ ์ ์์์ ๋ํ๋ด์ด, ์ ์ง๋ณด์๊ฐ ์ด๋ ต๊ณ ์ฌ์ฌ์ฉ์ฑ์ด ๋ฎ์ ๊ฐ๋ฅ์ฑ์ด ๋๋ค.
์ค์น ๋ฐ ์ค์
npm i tsyringe reflect-metadata
main.tsx
์ฑ์ด ์์๋๋ ๋ถ๋ถ์ reflect-metadata ์ํฌํธ ์์ผ์ค๋ค. src/setupTests.ts ํ์ผ๋ ์๋ค๋ฉด ์์์ ์ ๋๊ฐ์ด ์ํฌํธ ์์ผ์ค๋ค.
import 'reflect-metadata';
tsconfig.json
Tsyringe ์์ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์, tsconfig.json ์ฝ๋ ๋ณ๊ฒฝ
{
"compilerOptions": {
...
"experimentalDecorators": true,
"emitDecoratorMetadata": true
...
}
}
Store ํด๋์ค๋ฅผ ๋ง๋ค์ด count ๋ณ์์ ๊ด๋ฆฌ์ UI ์
๋ฐ์ดํธ๋ฅผ ํด๋ณด์
// scr/stores
import { singleton } from 'tsyringe';
type Listener = () => void;
@singleton()
export default class CounterStore {
count = 0;
// ์ธ๋ถ forUpdate ๋ฅผ ๋ฑ๋กํ๋ ์ฉ๋
// set ์ ํ ์ด์ ๋, ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ๊ฐ์ forceUpdate ๋ฅผ ๋ฑ๋กํ์ ๋ ๋ฎ์ด์ฐ๋ ๊ฒ์
// ๋ฐฉ์งํ๊ธฐ ์ํจ์ด๋ค.
listeners = new Set<Listener>();
// ์ธ๋ถ์์ ๋ฐ์์จ forUpdate ๋ฅผ ์คํํ๋ ์ฉ๋
publish() {
this.listeners.forEach((listener: Listener) => listener());
}
// ๋น์ง๋์ค ๋ก์ง
// ์ ์ญ๊ฐ์ด? ๊ด๋ฆฌ๋๋ ํด๋์ค์ ๋ฉค๋ฒ๋ณ์๋ฅผ ์
๋ฐ์ดํธ ํ ํ์,
// publish ๋ฅผ ํตํ์ฌ forceUpdate ๋ฅผ ์คํํ์ฌ, ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ ๋ก ๋ฆฌ๋ ๋๋งํ๋ค.
increase() {
this.count += 1;
this.publish();
}
// ๋น์ง๋์ค ๋ก์ง
decrease() {
this.count -= 1;
this.publish();
}
// ๋ฆฌ์ค๋(forceUpdate ํจ์) ๋ฅผ ๋ฑ๋กํ๊ธฐ ์ํ ๋ฉ์๋
addListener(listener: Listener) {
this.listeners.add(listener);
}
// ๋ฆฌ์ค๋(forceUpdate ํจ์) ๋ฅผ ๋ฑ๋กํด์ ํ๊ธฐ ์ํ ๋ฉ์๋
deleteListener(listener: Listener) {
this.listeners.delete(listener);
}
}
Store ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ๊ณณ์์๋ ํจ์ฌ ๋ ๊ฐํธํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
import useCounterStore from '../hooks/useCounterStore';
export default function CounterControl() {
const store = useCounterStore();
const handleIncrease = () => {
store.increase();
};
const handleDecrease = () => {
store.decrease();
};
return (
<div>
<p>{store.count}</p>
<button type='button' onClick={handleIncrease}>
Increase
</button>
<button type='button' onClick={handleDecrease}>
Decrease
</button>
</div>
);
}
import useCounterStore from '../hooks/useCounterStore';
export default function Counter() {
const store = useCounterStore();
return (
<div>
<p>Count {store.count}</p>
</div>
);
}
Last updated