The principle of IoC says that we don't call the framework, the framework calls us.
์ธ๋ถ์ API(๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๊ณต API, ์ธ์ด ์ ๊ณต ๋ฉ์๋ ๋ฑ)์์ ์คํ๋ ์์ ์ ์ฌ์ฉ์(ํ๋ก๊ทธ๋๋จธ) ์ชฝ์ผ๋ก ๋๊ธฐ๋ ๊ฒ
์ข์ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์ ์ค ํ๋๋ ๋ณดํธ์ ์ธ ๊ธฐ๋ฅ์ ์ถ์ํ ๊ณ์ธต์ ์ ๊ณตํ๊ณ ๊ทธ๊ฒ์ ์ฌ์ฌ์ฉํ๋๋ก ํ๋ ๊ฒ์ด๋ค.
๋ค์๊ณผ ๊ฐ์ ์์๋ฅผ ๋ค ์ ์๊ฒ ๋ค.
function calculator(a, b, option) {
switch (option) {
case "add":
return a + b;
case "sub":
return a - b;
case "mul":
return a * b;
case "div":
return a / b;
default:
return 0;
}
}
console.log(calculator(1, 5, "sub"));
๋ง์ฝ ๊ณ์ฐ ์์ ์ ํ๋ ๊ธฐ๋ฅ์ ์ฌ์ฌ์ฉ์ฑ์ ์ํด ๋ค์๊ณผ ๊ฐ์ด ๋ง๋ค์๋ค๊ณ ํด๋ณด์. ์ฌ์ฌ์ฉ ์ธก๋ฉด์์ ์ถฉ๋ถํ ์ ๊ธฐ๋ฅ์ ํ๋ ํจ์์ด์ง๋ง ๋ช ๊ฐ์ง ๋จ์ ์ด ์๋ค.
์ฐ๋ฆฌ๊ฐ ๋ช ๊ฐ์ ๊ธฐ๋ฅ์ ๋ ์ถ๊ฐํ๋ค๊ณ ๊ฐ์ ํด๋ณด์. ๊ฐ๊ฐ a์, b๋ฅผ ์ ๊ณฑํด์ ๋ํ๋ ๊ฒ, ๊ทธ๋ฆฌ๊ณ a์ b์ ์ ๋๊ฐ์ ๊ตฌํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํด๋ณด์.
function calculator(a, b, option) {
switch (option) {
case "add":
return a + b;
case "sub":
return a - b;
case "mul":
return a * b;
case "div":
return a / b;
case "power":
return a ** 2 + b ** 2;
case "abs":
return Math.abs(a - b);
default:
return 0;
}
}
console.log(calculator(3, 6, "power"));
console.log(calculator(1, 5, "abs"));
๋ค์๊ณผ ๊ฐ์ ํํ๋ก ๊ธฐ๋ฅ์ด ์์ ๋ ๊ฒ ๊ฐ๋ค.
๋ฒ์จ๋ถํฐ ๋์ ๋์๊ฐ ํํ ํ๊ธด๋ค. ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ฉด ํ ์๋ก ํจ์๋ ๊ฑฐ๋ํด์ง๊ณ , ๊ทธ๊ฒ์ ์ฌ์ฉํ๋ ์ฌ์ฉ์ ๋ํ ํจ์์ ์ฌ์ฉ๋ฒ์ ์ตํ๋ ๋ฐ ๋ถ๋ด์ ๋๋ ๊ฒ์ด๋ค.
๋น์ฐํ ์ ์ง๋ณด์ ์ธก๋ฉด์์๋ ์ ์ข์์ง๊ธฐ ๋๋ฌธ์, ์๊ตฌ ์ฌํญ์ ๋ชจ๋ ๋ฐ์ํ๊ธฐ์๋ ์ด๋ฐ ๊ตฌ์กฐ๊ฐ ์ข์ ๋ฐฉ์์ ์๋๋ค.
function IOCCalculator(a, b, callback) {
return callback(a, b);
}
console.log(IOCCalculator(5, 6, (a, b) => a + b));
console.log(IOCCalculator(5, 6, (a, b) => a ** 2 + b ** 2));
์์ ๊ฐ์ ๊ตฌ์กฐ๋ก ๊ฐ์ ํ๋ค.
์ฌ์ค ๊ฐ์ ์ด๋ผ๊ณ ๋งํ๊ธฐ๋ ์กฐ์ฌ์ค๋ฌ์ด ๋ถ๋ถ์ด์ง๋ง, ๋ง์ฝ ์ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค๋ฉด ํด๋น ํจ์ ๋ด์ ๋ก์ง์ ์ถ๊ฐํด ๋ก๊น ์ด๋, validation ์ฒดํฌ ๋ฑ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ ์ ์๋ค.
function IOCCalculator(a, b, callback) {
console.log(`${a} calc ${b} = ${callback(a, b)});
return a < b ? callback(a, b) : 0;
}
console.log(IOCCalculator(5, 6, (a, b) => a + b));
console.log(IOCCalculator(5, 6, (a, b) => a ** 2 + b ** 2));
์ด๋ฐ ๋ฐฉ์์ด ๋ฐ๋ก ์ ์ด์ ์ญ์ ์ด๋ค. ์ ์ด์ ์ญ์ ์ด๋ผ๋ ๋ง์ด ์กฐ๊ธ ์ด๋ ต๋ค. ์ ๊ทธ๋ฐ ์ด๋ฆ์ผ๋ก ๋ถ๋ฅด๋ ์ง ์ดํด๋ณด์.
๊ธฐ๋ณธ์ ์ธ ํ๋ก๊ทธ๋๋ฐ์์ ํ๋ก๊ทธ๋จ์ ํ๋ฆ์ ๋ช ๋ นํ์ผ๋ก ์งํ๋๋ค.
์๋ฅผ ๋ค์ด ์ข ์ด ๋นํ๊ธฐ๋ฅผ ์ ๋๋ค๊ณ ํ์ ๋๋ฅผ ์๊ฐํด๋ณด์.
์ด์ฒ๋ผ ๋ชจ๋ ๋์๋ค์ ํ๋ํ๋, ๊ทธ๋ฆฌ๊ณ ์์์ ๋ง์ถฐ ์ํํด์ผํ๋ค.
์ด๋ ๊ฒ ์ธ๋ถ์ ์ธ ์์๋ค์ ๋ชจ๋ ์ธ์ด๋ฅผ ์์ฑํ๋ ์ชฝ์์ ์ํํ๋ ๊ฒ ์ผ๋ฐ์ ์ธ ํ๋ก๊ทธ๋๋ฐ์ ํ๋ฆ์ด๋ค.
์์ ์์์์ ์ด๊ธฐ calculator๊ฐ ๊ทธ๋ฐ ๋ฐฉ์์ด๋ค. ์ด๋ฐ ๊ตฌํ์ ๋จ์ ์ ๋ชจ๋ usecase์ ๋์ํ ์ ์๋๋ก ๊ธฐ๋ฅ์ ์์ฑํด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
๋ํ ์ถํ ๊ธฐ๋ฅ์ ๊ฐ์ ํ ๋, ๋ถํ์ํ๋ค๊ณ ์๊ฐ๋๋ ๊ธฐ๋ฅ์ ๋นผ๊ณ ์ถ์ด๋ ์ฝ์ง ์๋ค. ๊ธฐ์กด์ ํด๋น ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๋ถ๋ถ์ด ์์๋ค๋ฉด ๋ฌธ์ ๋ฅผ ๋ฐ์์ํค๊ธฐ ๋๋ฌธ์ด๋ค.
ํ์ง๋ง ์ํ๋์ด์ผ ํ ๊ธฐ๋ฅ์ ์ผ๋ถ๋ถ์ ์ฌ์ฉ์(ํ๋ก๊ทธ๋๋จธ) ์ธก์ผ๋ก ๋๊ธด๋ค๋ฉด ๋ค์ํ usecase์ ํจ์จ์ ์ผ๋ก ๋์ํ ์ ์๋ค.
์ฝ๋๋ฅผ ์์ฑํ์ง๋ง ๊ทธ๊ฒ์ ์คํํ๋ ๊ฒ์ ํธ์ถํ ๋ชจ๋์ด ๋๋ ๊ฒ์ด๋ค. ์ด๋ ๊ฒ ์ผ๋ฐ์ ์ธ ํ๋ฆ์์ ๋ฒ์ด๋ ํํ์ ์ค๊ณ๋ฅผ ์ ์ด์ ์ญ์ (Inversion of Control)์ด๋ผ๊ณ ํ๋ค.
์ฆ ์ฌ์ฉ์๊ฐ ์์ฑํ ์ฝ๋๊ฐ ํด๋น ๊ธฐ๋ฅ์ ์ผ๋ถ๋ถ์ผ๋ก ์๋ํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
์๊ฐ๋ณด๋ค ์ ์ด์ ์ญ์ ์ ํํ๊ฒ ์ผ๋ค. ๋จ์ง ๊ทธ๊ฒ์ด ์ ์ด์ ์ญ์ ์ด๋ผ๋ ๊ฐ๋ ์ธ์ง๋ ๋ชจ๋ฅด๊ณ ์์์ง๋ง... map, filter ๋ฑ ๋ค์ํ ๋ฐฐ์ด ๋ฉ์๋ ๋ํ ์ ์ด์ ์ญ์ ํจํด์ด๋ผ๊ณ ๋ณผ ์ ์๋ค.
const Board = ({ author, title, content, date }) => {
return (
<div>
<div>์์ฑ์: {author}</div>
<div>
์ ๋ชฉ: {title}, ๋ ์ง {date}
</div>
<div>๋ด์ฉ: {content}</div>
</div>
);
};
function App() {
const { author, title, content, date } = {
author: "lee",
title: "My simple Board",
content: "Hello this is my First Board",
date: "today",
};
return (
<div className='App'>
<Board author={author} title={title} content={content} date={date} />
</div>
);
}
๋ค์๊ณผ ๊ฐ์ ์ปดํฌ๋ํธ๊ฐ ์๋ค๊ณ ํด๋ณด์. Board ์ปดํฌ๋ํธ์ ๋ฌธ์ ์ ์ ์ฐพ์๋ณด์.
Board ์ปดํฌ๋ํธ๋ props๋ก ์์ฑ๋ค์ ๋ฐ์ ๊ทธ๊ฒ์ ๋ ๋๋งํ๊ณ ์๋ค. ์ด๋ ๋ฌธ์ ๋ ์ด๋ค props๊ฐ ๋ค์ด์ค๋์ง ์ ํํ ์์์ผ ํ๊ณ , ๋ง์ฝ ์๋ก์ด props๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค๋ฉด ์ฌ์ฉ ์ธก๊ณผ ์ปดํฌ๋ํธ ์ธก ๋ชจ๋ ๊ทธ๊ฒ์ ๋ฐ์ํด์ผํ๋ค๋ ๊ฒ์ด๋ค.
const Board = ({ author, title, content, date, onClick }) => {
return (
<div
onClick={() => {
onClick(author);
}}
>
<div>์์ฑ์: {author}</div>
<div>
์ ๋ชฉ: {title}, ๋ ์ง {date}
</div>
<div>๋ด์ฉ: {content}</div>
</div>
);
};
function App() {
const { author, title, content, date, onClick } = {
author: "lee",
title: "My simple Board",
content: "Hello this is my First Board",
date: "today",
onClick: () => {
alert(`Hello!`);
},
};
return (
<div className='App'>
<Board
author={author}
title={title}
content={content}
date={date}
onClick={onClick}
/>
</div>
);
}
๋ง์ฝ ์ปดํฌ๋ํธ์ ์๊ตฌ์ฌํญ์ด ๋ฌ๋ผ์ ธ ํน์ ์์๋ค์ ์ถ๊ฐํด์ผํ๋ค๋ฉด ์์ ๊ฐ์ด ์์ ํ ์ ์๋ค. ์์์์ ํด๋ฆญ ์ด๋ฒคํธ์ ์กฐํ์๋ฅผ ์ถ๊ฐํ๋ค.
๋ฒ์จ๋ถํฐ ์ฌ์์น ์์ ๋๋์ด ๋ ๋ค. ์ด๋ ๊ฒ ๊ตฌํํ๋ค๋ฉด props์ ๊ธธ์ด๊ฐ ์ ์ ๋์ด๋ ์ฝ๋๊ฐ ๊ดด๋ฌผ์ด ๋์ด๋ฒ๋ฆด ๊ฒ ๊ฐ๋ค.
์ง๊ธ์ ๊ทธ๋๋ง ๋จ์ํ ๊ตฌ์กฐ์ด์ง๋ง, ํน์ props ์กฐ๊ฑด์ ๋ฐ๋ผ props๋ค์ ์์น๊ฐ ๋ฐ๋๋ค๋์ง ๊ทธ๋ฐ ๋ถ๋ถ๋ค์ ์์ํด๋ณด๋ฉด ๋์ฐํ ์ฝ๋๊ฐ ๋ง๋ค์ด์ง ๊ฒ์ด ๋ถ๋ช ํ๋ค.
const Board = ({ onClick, children }) => {
return (
<div
onClick={() => {
onClick();
}}
>
{children}
</div>
);
};
function App() {
const { author, title, content, date, views, onClick } = {
author: "lee",
title: "My simple Board",
content: "Hello this is my First Board",
date: "today",
views: 15,
onClick: () => {
alert(`Hello!`);
},
};
return (
<div className='App'>
<Board onClick={onClick}>
<div>์์ฑ์: {author}</div>
<div>์กฐํ์: {views}</div>
<div>
์ ๋ชฉ: {title}, ๋ ์ง {date}
</div>
<div>๋ด์ฉ: {content}</div>
</Board>
</div>
);
}
์ด๋ฐ ๊ตฌ์กฐ๋ ์ด๋จ๊น? ์ด ์ฝ๋์ ์์ ์๋ IOCCalulator์ ๊ตฌ์กฐ๋ฅผ ๋น๊ตํด๋ณด์. ๋น์ทํ ๊ตฌ์กฐ๋ผ๊ณ ๋๊ปด์ง๋ค. IOCCalulator์ฒ๋ผ Board ์ปดํฌ๋ํธ๋ ๋ฐ์ children์ ๋ ๋๋งํ ๋ฟ, ๊ทธ๊ฒ์ด ๋ฌด์์ธ์ง๋ ๊ด์ฌ์ฌ๊ฐ ์๋๋ค.
ํ์ง๋ง ์ด๋ฐ ๋ฐฉ๋ฒ์ ์ข์ ์ ๋ง ์๋ ๊ฑด ์๋๋ค. ๋ง์ฝ ๊ฐ์ Board์ธ๋ฐ author์ views๊ฐ ํ์ ๋ฒ ์งธ Board์์๋ง ์์น๊ฐ ๋ฐ๋๋ค๊ณ ์๊ฐํด๋ณด์. ๋งค๋ฒ ์ํฉ์ ๋ฐ๋ผ children์ผ๋ก ๋ค์ด๊ฐ ์์๋ฅผ ๋ฐ๊ฟ์ค์ผํ๋ค.
๋ฌผ๋ก ์ด๋ฐ ๊ฒ๋ ์ถฉ๋ถํ ์ถ์ํ ๊ณ์ธต์ ์ ๊ณตํด์ ํด๊ฒฐํ ์ ์๋ค. OddBoardContent, EvenBoardContent ๋ฑ์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด ์ฌ์ฌ์ฉํ๋ฉด ๊ทธ๋ง์ด๋ค.
const Counter = (props) => {
const [count, setCount] = useState(0);
return (
<div onClick={() => setCount((prev) => prev + 1)}>
props.children
</div>
);
};
render props ๋ํ IoC ํจํด์ผ๋ก ์ฌ์ฉํ ์ ์๋ค. Counter ์ปดํฌ๋ํธ์ count๋ฅผ children์ ์ด๋ป๊ฒ ์ ๋ฌํ ๊น? count๊ฐ ์ ๋ฐ์ดํธ๋ ๋๋ง๋ค children๋ ๊ฐ์ด ์ ๋ฐ์ดํธ ํด๋ณด์.
const Counter = (props) => {
const [count, setCount] = useState(0);
return (
<div onClick={() => setCount((prev) => prev + 1)}>
{props.children(count)}
</div>
);
};
function App() {
const { author } = {
author: "lee",
};
return (
<div className='App'>
<Counter>
{(count) => {
return (
<>
<div>์์ฑ์: {author}</div>
<div>{count}</div>
</>
);
}}
</Counter>
</div>
);
}
children์ ํจ์๋ฅผ ์ ๋ฌํ๊ณ ๊ทธ๊ฒ์ Counter ์ปดํฌ๋ํธ๊ฐ ํธ์ถํ๊ณ ์๋ค. ์ด๋ฐ ํ์์ผ๋ก ์์ฑํ๋ค๋ฉด ๋งค state ์ ๋ฐ์ดํธ๋ง๋ค, children ํจ์๋ฅผ ์ฌ์คํํ๋ค.
๊ทธ๋ฐ ๋งํผ children์ ๋ ๋๋ง ๋น์ฉ์ด ๋น์ธ์ง๋ฉด ์ ๋๊ธฐ ๋๋ฌธ์ ์ ์ ํ๊ฒ ์ฝ๋๋ฅผ ๋๋๊ฑฐ๋ ์ฌ์ฉ ์์ฒด์ ๋ํด ๊ณ ๋ คํด๋ด์ผํ๋ค.
์ ์ด์ ์ญ์ ๊ฐ๋ ์ ๋ํด ์ดํด๊ฐ ์ ๋์ง ์์์ ๊ธ์ ์์ฑํ๋๋ฐ ์ค๋ ์๊ฐ์ด ๊ฑธ๋ ธ๋ค.
์ฌ์ค ์ด ํจํด์ ์๊ฒ ๋ชจ๋ฅด๊ฒ ๋ง์ด ์ฌ์ฉํ๊ณ ์๋ค. ๋น์ฅ ๋ฆฌ์กํธ์ ์ ์ฒด์ ์ธ ์๋๋ง ๋ด๋ ์ ์ด์ ์ญ์ ์ด๋ค. ์ฐ๋ฆฌ๋ ๋จ์ํ JSX์ ๋ก์ง๋ค์ ์์ฑํ ๋ฟ์ด์ง๋ง, ๋ฆฌ์กํธ๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ๋ค์ ๋ณด์.
V-DOM, ๋ฆฌ๋ ๋๋ง, props ๋ฑ ๋ฆฌ์กํธ ๋ด๋ถ์์ ๋์์ธ ๋ ๊ธฐ๋ฅ๋ค์ด๋ค. ๊ทธ๊ฒ์ด ์ด๋ป๊ฒ ๋์ํ๋์ง๋ ์ฐ๋ฆฌ์ ๊ด์ฌ์ฌ๊ฐ ์๋๋ค. ์ ์ด์ ์ญ์ ์ ์กฐ๊ธ ๋ ์ ์ฐํ ์ถ์ํ์ธ๊ฐ?
๋๊ตฐ๊ฐ ๋์๊ฒ ์ ์ด์ ์ญ์ ์ ๋ํด ๋ฌป๋๋ค๋ฉด ๋๋ต์ ํ ์ ์๊ฒ ์ง๋ง, ๋ด ๋๋น์ ํ์ ์ ์ฐจ์์ง ๋ชปํ ๊ฒ ๊ฐ๋ค.
https://kentcdodds.com/blog/inversion-of-control
https://www.lorenzweiss.de/inversion_of_control_with_react_components/
https://brunch.co.kr/@finda/556
์ ๋ฌธ์๋ค์ ์ฐธ๊ณ ํ์ต๋๋ค.