External Store
ํ์ตํค์๋
๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ
Architecture
Layered Architecture
Flux Architecture
MVC ํจํด
External Store
๊ด์ฌ์ฌ ๋ถ๋ฆฌ
๐ ๊ด์ฌ์ฌ ๋ถ๋ฆฌ(Separation of Concerns)
์ปดํจํฐ ํ๋ก๊ทธ๋จ์ ๊ตฌ๋ณ๋ ๋ถ๋ถ์ผ๋ก ๋ถ๋ฆฌ์ํค๋ ๋์์ธ ์์น์ผ๋ก, ๊ฐ ๋ถ๋ฌธ์ ๊ฐ๊ฐ์ ๊ด์ฌ์ฌ๋ฅผ ํด๊ฒฐํ๋ค.
ํ๋์ ๋ชจ๋(ํน์ ํจ์)๊ฐ ์ฌ๋ฌ๊ฐ์ง์ ๊ด์ฌ์ฌ๋ฅผ ๊ฐ์ง๊ณ ์ฒ๋ฆฌํ๋ ค๋ฉด ๋ณต์ก์ฑ์ด ๋์์ง๋ ๊ด์ฌ์ฌ๋ฅผ ์ฌ๋ฌ๊ฐ๋ก ๋ถ๋ฆฌํ์ฌ ํ๋์ ๊ด์ฌ์ฌ๋ ํ๋์ ๊ธฐ๋ฅ์(์ญํ๋ง) ๊ฐ์ง๋๋ก ๊ตฌ์ฑํ๋ ๊ฒ
๐ค ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ๋ ์ด์ ๋?!?
ํ๋์ ํ๋ก๊ทธ๋จ์ ์์ ๋ถํ์ด ๋ชจ์ฌ์ ๋ง๋ค์ด์ง๋ค. React๋ ์์ ์ปดํฌ๋ํธ๋ค์ ์กฐ๋ฆฝํ์ฌ ๋ ํฐ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋๋ ๋ฐฉ์์ผ๋ก ๊ฐ๋ฐํ๊ณ ์๋ค.
์๋ฅผ ๋ค์ด, ์๋์ ๊ฐ์ด ๋ํ ๋ผ ์ ์๋ค. ์ด๋ ๊ธฐ๋ฅ
์ ์์ฃผ๋ก ๋ถ๋ฆฌํ๋ค.
- App
- Header
- Main
- Greeting
- Counter
- Posts
- PostForm
- TextField
- Footer
์ด๋ฐ ์์ผ๋ก ๋ถ๋ฆฌํ๋ ์ด์ ๋ ๋ฌด์์ผ๊น? ์๋ก์ ๊ด์ฌ์ฌ
๊ฐ ๋ค๋ฅด๋ค.
์๋ฅผ ๋ค์ด, App์์๋ TextField๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ์ ํ์๊ฐ ์๋ค. ๊ฐ ๋ถ๋ถ์ ํ๋์ ์ญํ , ํ๋์ ๊ด์ฌ์ฌ๋ก ๊ฒฉ๋ฆฌ ๋จ์ผ๋ก์จ, ๋ณต์ก๋๋ฅผ ๋ฎ์ถ๊ฒ ๋๋ค.
Architecture
์์คํ ์ํคํ ์ฒ(system Architecture)๋ ์์คํ ์ ๊ตฌ์กฐ, ํ์, ๋ ๋ง์ ๋ทฐ๋ฅผ ์ ์ํ๋ ๊ฐ๋ ์ ๋ชจํ์ด๋ค. ์์คํ ๋ชฉ์ ์ ๋ฌ์ฑํ๊ธฐ ์ํด ์์คํ ์ ๊ฐ ์ปดํฌ๋ํธ๊ฐ ๋ฌด์์ด๋ฉฐ ์ด๋ป๊ฒ ์ํธ์์ฉํ๋์ง, ์ ๋ณด๊ฐ ์ด๋ป๊ฒ ๊ตํ๋๋์ง๋ฅผ ์ค๋ช ํ๋ค.
โ ์ฆ, ์๋น์ค์ ๋์ ์๋ฆฌ๋ฅผ ๋ํ๋ด๋ ๊ฒ ์ ์๋ฏธํ๋ค.
์ํํธ์จ์ด ์ํคํ
์ฒ
์์คํ ์ ์ ์ฒด์ ์ธ ๊ตฌ์กฐ์ ๊ตฌ์ฑ์์๋ค ๊ฐ์ ์ํธ์์ฉ์ ์ค๊ณํ๋ ๊ฒ
์์คํ ์ ์ ์ฒด์ ์ธ ๋์์ ๊ฒฐ์ ํ๊ณ , ์์คํ ์ ํ์ง ์ฑ๋ฅ(์ฑ๋ฅ, ํ์์ฑ, ์ ์ง๋ณด์์ฑ, ๋ณด์ ๋ฑ)์ ์ง์ ์ ์ผ๋ก ์ํฅ์ ๋ฏธ์น๋ค.
Layered Architecture
์ํํธ์จ์ด ์์คํ ์ ๊ด์ฌ์ฌ ๋ณ๋ก ์ฌ๋ฌ๊ฐ์ ๊ณ์ธต๋ก ๋ถ๋ฆฌ(๊ณ์ธตํ)ํ ์ํคํ ์ฒ
๊ฐ ๊ณ์ธต์ ์ดํ๋ฆฌ์ผ์ด์ ๋ด์์ ํน์ ์ญํ ๊ณผ ์ฑ ์์ด ์๋ค. ๊ทธ๋ค์ ์์ ์ ์ญํ ์๋ง ์ง์คํ๋ค. ์ฌ๊ธฐ์ ์ค์ํ ๊ฒ์ ๊ตฌ์ฑ ์์๊ฐ ๊ด์ฌ์ฌ๊ฐ ๋ถ๋ฆฌ๋์๋ค๋ ์ ์ด๋ค.

Layered Architecture ์ฅ์
์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ ๋ฐ ์ ์ง๋ณด์์ฑ
๊ฐ ๊ณ์ธต์ด ๊ด์ฌ์ฌ๋ณ๋ก ๋ถ๋ฆฌ๋์ด ์์ผ๋ฏ๋ก
๋ณํ์ ์ ์ฐํ๊ฒ ๋์ฒ
๊ฐ ๊ณ์ธต์ด ๋ ๋ฆฝ์ ์ผ๋ก ๊ฐ๋ฐ,ํ์ฅ,๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ๋ค.
ํ ์คํธ ์ฉ์ด์ฑ
๊ฐ ๊ณ์ธต์ด ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธ ๊ฐ๋ฅํ๋ฏ๋ก ๋จ์ ํ ์คํธ๋ ํตํฉ ํ ์คํธ ์ฉ์ดํ๊ฒ ์ํ
Layered Architecture ๋จ์
์ค๋ฒํค๋
๊ณ์ธต๊ฐ์ ํต์ ์ ํตํด ๋์ํ๊ธฐ ๋๋ฌธ์,(๋จ๋ฐฉํฅ ์์กด์ฑ) ๋ฐ์ดํฐ์ ์ ๋ฌ ๋ฐ ๋ณํ ๊ณผ์ ์์ ์ผ๋ถ ์ค๋ฒํค๋ ๋ฐ์
๋ณต์ก์ฑ
๊ณ์ธต๊ฐ์ ํต์ ์ ์ํ ์ธํฐํ์ด์ค์ ๋ก์ง์ ์ถ๊ฐํด์ผํ๋ฏ๋ก ๋ณต์ก์ฑ์ด ์ฆ๊ฐ
Flux Architecture
๐ Flux Architecture ํ์ ๋ฐฐ๊ฒฝ

๊ธฐ์กด์ 2-way binding(์๋ฐฉํฅ ๋ฐ์ธ๋ฉ)์ ์ผ์ ๋ ์๊ธธ ์ ์๋ Model-View์ ๋ณต์กํ ๊ด๊ณ(์ ํต์ ์ธ MVC์์ ์ด๋ฐ ์ํฉ์ ์ง์)๋ฅผ ๊ฒจ๋ฅํ์ฌ Facebook(ํ Meta)์์ MVC ํจํด์ ํ๊ณ์ ๋์์ผ๋ก ๋ด์ธ์ด ์ํคํ ์ฒ๋ฅผ ์๋ฏธํ๋ค.
๐ค 2-way binding ์๋ฐฉํฅ ๋ฐ์ธ๋ฉ?
๐ ๋ฐ์ดํฐ(Data Binding)์ด๋? ํ๋ฉด์์ ๋ณด์ฌ์ง๋ ๋ฐ์ดํฐ(View)์ ๋ธ๋ผ์ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์๋ ๋ฐ์ดํฐ(Model)๋ฅผ ๋ฌถ์ด์(Binding) ์๋ก ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋๊ธฐํ ํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
Javascript(Model)์ HTML(View) ์ฌ์ด์ ViewModel์ด ์กด์ฌํ์ฌ ํ๋๋ก ๋ฌถ์ฌ์(Binding)๋์ด์ ๋ ์ค ํ๋๋ง ๋ณ๊ฒฝ๋์ด๋ ํจ๊ป ๋ณ๊ฒฝ๋๋ ๊ฒ์ ์๋ฏธํ๋ค.
HTML(View) ๐ ViewModel ๐ Javascript(Model)

๐ค Flux ์์คํ
์ ๊ตฌ์กฐ

unidirectional data flow(๋จ๋ฐฉํฅ ํ๋ฆ)์ ๊ฐ์ง๋ Architecture์ด๋ค. ๋ฐ์ดํฐ์ ํ๋ฆ์ Dispatcher โ Store โ View ํ๋ฅด๊ณ View์์ ์ ๋ ฅ์ด ๋ฐ์ํ๊ฒ ๋๋ฉด Action์ ํตํด ๋ค์ Dispatcher๋ก ํฅํ๊ฒ ๋๋ค.
Action : ๋ฐ์ดํฐ ํ๋ฆ์ ๋ณํ๋ฅผ ์ฃผ๊ธฐ ์ํ ๋์ ๋ฐ์ โ ์ด๋ฒคํธ/๋ฉ์์ง ๊ฐ์ ๊ฐ์ฒด
Dispatcher : Action์ ๋ฐ์กํ๋ ์ญํ โ (์ฌ๋ฌ)Store๋ก Action์ ์ ๋ฌ
Store : ๋ฐ์ดํฐ๋ค์ ์ ์ฅํ๋ ๊ณต๊ฐ โ ๋ฐ์ Action์ ๋ฐ๋ผ ์ํ๋ฅผ ๋ณ๊ฒฝ/์ํ ๋ณ๊ฒฝ์ ์๋ฆผ.
Dispatcher๋ฅผ ํตํด ๋ณํ๋ ๋ฐ์ดํฐ๊ฐ Store ์ ์ฅ
View : Store์ ์ํ๋ฅผ ๋ฐ์, ๋ ๋ค๋ฅธ Action์ ์ ๋ฌ ํด์ค๋ค.
External Store
External Store : (React ์ ์ฅ์์) Store๊ฐ React์ ์์ ์์ง ์๋๋ค๋ฅผ ์๋ฏธํ๋ค.
useState ๋ก ์ํ ๊ด๋ฆฌ
Increase ๋ฒํผ์ ๋๋ฅด๋ฉด count ๊ฐ 1์ฉ ์ฆ๊ฐํ๋ค. ํ๋ฉด์๋ ์ฆ๊ฐ๋๋ ์ํ ๊ฐ์ด ๋ณด์ธ๋ค.
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
<p>{count}</p>
<button type="button" onClick={handleClick}>
Increase
</button>
</div>
);
}
๐จ ์ผ๋ฐ์ ์ธ ๋ณ์๋ก ์ ์ธํ ์ํ๋ฅผ ๋ณ๊ฒฝ์ ๋ฌธ์ ๋ฐ์
useState ์ฌ์ฉํ์ง ์๊ณ ์ผ๋ฐ์ ์ธ ๋ณ์๋ก ์ ์ธ๋ ์ํ๋ฅผ ๋ณ๊ฒฝํ์ง๋ง ํ๋ฉด์ ๋ณํ๋ ์ํ๊ฐ์ด ๋ฐ์๋์ง ์๋๋ค.
import { useEffect } from 'react';
let count = 0;
export default function Counter() {
useEffect(() => {
console.log(count);
});
const handleClick = () => {
count += 1;
//console.log(count);
};
return (
<div>
<p>{count}</p>
<button type="button" onClick={handleClick}>
Increase
</button>
</div>
);
}
useReducer๋ฅผ ํตํด (feat.forceUpdate)
Class ์ปดํฌ๋ํธ๋ฅผ ์ฐ๋ ์์ ์๋ forceUpdate ํจ์๋ฅผ ํตํด ๊ฐ์ ๋ก ๋ฆฌ๋ ๋๋ง์ ํ๋ค. ๊ทธ๋ฌ๋ Function ์ปดํฌ๋ํธ๋ useReducer hook์ ์ฌ์ฉํด์ ์ํ๋ฅผ ๋ฆฌ๋ ๋๋ง ํจ์ผ๋ก์ ํด๊ฒฐ
import { useEffect, useReducer } from 'react';
let count = 0;
export default function Counter() {
// const [ignored, forceUpdate] = useReducer(x => x + 1, 0);
const [, forceUpdate] = useReducer(x => x + 1, 0);
useEffect(() => {
console.log(count);
});
const handleClick = () => {
count += 1;
// ๊ฐ์ ๋ก ๋ฆฌ๋ ๋๋ง
forceUpdate();
};
return (
<div>
<p>{count}</p>
<button type="button" onClick={handleClick}>
Increase
</button>
</div>
);
}
import { useEffect, useReducer } from 'react';
let count = 0;
function reducer(state){
// return state + 1;
return {...state, x : state.x + 1 }
}
export default function Counter() {
// const [ignored, forceUpdate] = useReducer(x => x + 1, 0);
// const [, forceUpdate] = useReducer(reducer, 0);
const [, forceUpdate] = useReducer(reducer, {x:0});
useEffect(() => {
console.log(count);
});
const handleClick = () => {
count += 1;
// ๊ฐ์ ๋ก ๋ฆฌ๋ ๋๋ง
forceUpdate();
};
return (
<div>
<p>{count}</p>
<button type="button" onClick={handleClick}>
Increase
</button>
</div>
);
}
๐ค ๊ทธ๋ฌ๋ Counter ์ปดํฌ๋ํธ๋ ํ๋ฉด์ ์ ๋ฐ์ด๋ ํ๋ ์ํ์ count๋ฅผ ๋ณ๊ฒฝํ๋ ์ํ๋ฅผ ๋ชจ๋ ๊ฐ์ง๊ณ ์๋ค.
CustomHook์ผ๋ก ๋ถ๋ฆฌ
ํ๋ฉด์ ๋ ๋๋ง ํ๋ useState๋ฅผ CustomHook์ ํตํด ๋ถ๋ฆฌํ๋๋, React๊ฐ ๋์ด์ ํ๋ฉด์ ์ ๋ฐ์ดํธ ํ๋ ์ํ๋ ๊ด๋ฆฌ ํ์ง ์๊ฒ ๋์๋ค. ์ด๋ฐ์์ผ๋ก ๋ง๋๋๊ฒ External Store์ ๊ธฐ๋ณธ์ ์ธ ์์ด๋์ด๋ค.
// hooks/useForceUpdate.ts
import { useState} from 'react';
export default function useForceUpdate() {
const [state, setState] = useState(0);
const forceUpdate = () => {
setState(state + 1);
};
return forceUpdate;
}
// components/Counter.tsx
import useForceUpdate from '../hooks/useForceUpdate';
let count = 0;
export default function Counter() {
const forceUpdate = useForceUpdate();
const handleClick = () => {
count += 1;
forceUpdate();
};
return (
<div>
<p>{count}</p>
<button type="button" onClick={handleClick}>
Increase
</button>
</div>
);
}
External Store + ๊ด์ฌ์ฌ ๋ถ๋ฆฌ
import useForceUpdate from '../hooks/useForceUpdate';
// Business Logic
const state = {
count : 0,
};
function increase(){
state.count += 1;
}
// UI
export default function Counter() {
const forceUpdate = useForceUpdate();
const handleClick = () => {
increase();
forceUpdate();
};
return (
<div>
<p>{state.count}</p>
<button type="button" onClick={handleClick}>
Increase
</button>
</div>
);
}
์ด๋ฐ ์ ๊ทผ์ ํตํด์ React๊ฐ UI๋ฅผ ๋ด๋นํ๊ณ , ์์ํ TypeScript(๋๋ Javascript)๊ฐ ๋น์ฆ๋์ค ๋ก์ง์ ๋ด๋นํ๋ ๊ด์ฌ์ฌ ๋ถ๋ฆฌ ํตํด ์์ฃผ ๋ฐ๋๋ UI ์์์ ๋ํ ํ ์คํธ ๋์ , ์ค๋ ์ ์ง๋๋ ๋น์ฆ๋์ค ๋ก์ง์ ๋ํ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํด ์ ์ง๋ณด์์ ๋์์ด ๋๋ ํ ์คํธ ์ฝ๋๋ฅผ ์น๋ฐํ๊ฒ ์์ฑ ํ ์ ์๋ค.
๐ ์ฐธ๊ณ
Last updated