1. External Store

  • ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ

  • Layered Architecture

  • Flux Architecture

  • useReducer

  • useCallback

๊ฐ•์˜ ์ •๋ฆฌ

Separation of Concerns

๊ด€์‹ฌ์‚ฌ๋ฅผ ๋‚˜๋ˆ„๋Š” ๊ฒƒ

๋ฆฌ์•กํŠธ ์•ฑ์„ ๋งŒ๋“ค๋ฉด์„œ ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ๋ฅผ ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

App

  • Header

  • Main

    • Greeting

    • Counter

    • Posts

    • PostForm

      • TextField

    • Footer

App์€ TextField๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์•Œ๊ณ  ์‹ถ์ง€ ์•Š๋‹ค. TextField๋Š” Posts๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์•Œ๊ณ  ์‹ถ์ง€ ์•Š๋‹ค.

์„œ๋กœ ๊ด€์‹ฌ์‚ฌ๊ฐ€ ๋‹ค๋ฅด๊ณ  ๊ธฐ๋Šฅ๋“ค์ด ๋‹ค๋ฅด๋‹ค. ์œ„์˜ ์˜ˆ์‹œ๋Š” ๊ธฐ๋Šฅ์ด ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๋‚˜๋ˆด์ง€๋งŒ ์„ค๊ณ„, ์•„ํ‚คํ…์ฒ˜ ๊ด€์ ์—์„œ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.

Layered Architecture๋Š” ๋ฐฑ์—”๋“œ์—์„œ ๋งŽ์ด ์“ฐ์ด๋Š”๋ฐ, ํ”„๋ก ํŠธ์—”๋“œ์—์„œ๋„ ๋˜‘๊ฐ™์ด ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ ˆ์ด์–ด๋“œ ์•„ํ‚คํ…์ฒ˜๋Š” ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ๋ฐ”๋ผ๋ณธ๋‹ค.

์‚ฌ๋žŒ - ์Šค์œ„์น˜(UI) -> ๋ชจํ„ฐ -> ๋ฐ”ํ€ด

๊ฐ๊ฐ์€ ํ•˜๋‚˜์˜ ์—ญํ• ์„ ํ•œ๋‹ค. ์Šค์œ„์น˜๋Š” ON/OFF๋งŒ ํ•œ๋‹ค. ์ด๊ฑธ ๋ˆ„๋ฅด๋ฉด ON์ด ๋˜๊ณ , ๋‹ค์‹œ ๋ˆ„๋ฅด๋ฉด OFF๊ฐ€ ๋œ๋‹ค. ๋ชจํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋„๋Š”์ง€๋Š” ์ƒ๊ด€ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ณต์žก๋„๊ฐ€ ๋‚ฎ์•„์ง„๋‹ค. ๋ชจํ„ฐ๋Š” ์ „๋ฅ˜๊ฐ€ ํ๋ฅด๋ฉด ๋Œ์•„๊ฐ€๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค. ๊ฐ์ž ๋‹ค๋ฅธ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๊ฐ€์ง„๋‹ค.

๊ฑฐ๋Œ€ํ•œ ํ”„๋กœ๊ทธ๋žจ์ด ์•„๋‹ˆ๋ผ๊ณ  ํ•ด๋„ Input -> Process -> Output 3๋‹จ๊ณ„๋กœ ์ฝ”๋“œ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋ฉด, ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๋Š”๋ฐ ํฐ ๋„์›€์ด ๋œ๋‹ค. What's your name?

Input

Process -> Hello, [name] => ๋ฉ”์‹œ์ง€

function greeting(name: string) {
  return `Hello, ${name}`;
}

Output

ํ•˜๋‚˜์˜ Output์€ ๋‹ค์‹œ ์‚ฌ์šฉ์ž์—๊ฒŒ Input์„ ์š”์ฒญํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ์ด ์‹ธ์ดํด์ด ๊ณ„์† ๋ฐ˜๋ณต๋œ๋‹ค.

  1. Input: ํ”„๋กœ๊ทธ๋žจ ์‹œ์ž‘

  2. Process: ํ”„๋กœ๊ทธ๋žจ ์ดˆ๊ธฐํ™”

  3. Output: ์‚ฌ์šฉ์ž์—๊ฒŒ ์ดˆ๊ธฐ UI ๋ณด์—ฌ์ฃผ๊ธฐ

  4. Input: ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ

  5. Process: ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌ

  6. Output: ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ๋ณด์—ฌ์ฃผ๊ธฐ

  7. Input: ์‚ฌ์šฉ์ž์˜ ๋˜ ๋‹ค๋ฅธ ์ž…๋ ฅ

  8. โ€ฆ๋ฐ˜๋ณตโ€ฆ

์ด ๊ณผ์ •์„ MVC๋กœ ๊ฑฐ์น ๊ฒŒ ๋งคํ•‘ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค. (์‹ค์ œ๋กœ๋Š” ์•„๋‹ˆ์ง€๋งŒ)

  • Model -> Process

  • View -> Output

  • Controller -> Input

์„œ๋กœ ์ž๊ธฐ๊ฐ€ ํ•˜๋Š” ์ผ์—๋งŒ ์‹ ๊ฒฝ์„ ์จ์„œ ๊ทธ๊ฒƒ๋ง ์ž˜ ํ•˜๋ ค๊ณ  ํ•œ๋‹ค.

Flux Architecture

๋ฆฌ์•กํŠธ๋ฅผ ๋ฐœํ‘œํ•˜๊ณ  ๋‹ค์Œ ํ•ด์— ๋ฐœํ‘œ๋ฅผ ํ–ˆ๋‹ค. MVC์˜ ๋Œ€์•ˆ์œผ๋กœ ๋‚ด์„ธ์šด ์•„ํ‚คํ…์ฒ˜๋‹ค. (์—„๋ฐ€ํžˆ ๋งํ•˜๋ฉด ์˜์ƒ์—์„œ ์ฒ˜๋Ÿผ MVC๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค) View์˜ ๋ณต์žกํ•œ ๊ด€๊ณ„(์ „ํ†ต์ ์ธ MVC์—์„  ์ด๋Ÿฐ ์ƒํ™ฉ์„ ์ง€์–‘ํ•œ๋‹ค)๋ฅผ ๊ฒจ๋ƒฅํ•ด ๋ช…ํ™•ํžˆ unidirectional data flow๋ฅผ ๊ฐ•์กฐํ•œ๋‹ค.

  1. Action -> ์ด๋ฒคํŠธ/๋ฉ”์‹œ์ง€ ๊ฐ™์€ ๊ฐ์ฒด.

  2. Dispatcher -> (์—ฌ๋Ÿฌ) Store๋กœ Action์„ ์ „๋‹ฌ. ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค์™€ ์œ ์‚ฌํ•˜๋‹ค.

  3. Store (์—ฌ๋Ÿฌ ๊ฐœ) -> ๋ฐ›์€ Action์— ๋”ฐ๋ผ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ. ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์•Œ๋ฆผ.

  4. View -> Store์˜ ์ƒํƒœ๋ฅผ ๋ฐ˜์˜.

Redux๋Š” ๋‹จ์ผ Store๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์ข€ ๋” ๋‹จ์ˆœํ•œ ๊ทธ๋ฆผ์„ ์ œ์•ˆํ•œ๋‹ค.

  1. Action

  2. Store -> dispatch๋ฅผ ํ†ตํ•ด Action์„ ๋ฐ›๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜ํ•œ reducer๋ฅผ ํ†ตํ•ด State๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค.

  3. View -> State๋ฅผ ๋ฐ˜์˜.

๋ถˆ๋ณ€์„ฑ์„ ์ง€์ผœ์„œ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

const state = {
  name: 'tester',
};

const nextState = { ...state, name: 'New Name' };

reducer๋ฅผ ํ†ตํ•ด์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ด์ค€๋‹ค. reducer๋Š” ๋ฆฌ์•กํŠธ์™€๋Š” ์ƒ๊ด€์ด ์—†๋Š” ๊ฒƒ์ด๋‹ค.

Action์„ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ•˜๋А๋ƒ๊ฐ€ Redux๋ฅผ ์‚ฌ์šฉํ•จ์— ์žˆ์–ด ํฐ ์ฐจ์ด๋ฅผ ๋งŒ๋“ ๋‹ค. Action Creator๋„ ์กด์žฌํ•˜๋Š”๋ฐ, Action์„ ๋งŒ๋“ค์–ด๋‚ด๋Š” Helper ํ•จ์ˆ˜์˜ ์—ญํ• ์„ ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ƒํƒœ๋ฅผ UI์— ๋ฐ˜์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ชจ๋‘ ๋™์ผํ•˜๋‹ค.

3๋‹จ๊ณ„ ํ”„๋กœ์„ธ์Šค

  • Input -> Action + Dispatch

  • Process -> reducer

  • Output -> View(React)

External Store

๋ฆฌ์•กํŠธ๊ฐ€ ์•„๋‹Œ ๊ฒƒ, ๋ฆฌ์•กํŠธ์˜ ๋ฐ”๊นฅ์ธ ๊ฒƒ. ์ผ๋ฐ˜์ ์ธ ์•„ํ‚คํ…์ฒ˜ ๊ด€์ ์—์„œ ๋ดค์„ ๋•Œ UI๊ฐ€ ์˜คํžˆ๋ ค ๊ฐ€์žฅ ๋ฐ”๊นฅ์ชฝ, ์™ธ๋ถ€์™€ ๊ฐ€๊น๋‹ค. React๋Š” ์‚ฌ์‹ค ๋ฐ”๊นฅ์ชฝ์— ์žˆ๋Š” ๊ฒƒ.

์—ฌ๊ธฐ์„œ External Store์˜ ์˜๋ฏธ๋Š” ์•ˆ, ๋ฐ–์˜ ์˜๋ฏธ๋ผ๊ธฐ ๋ณด๋‹ค๋Š” React ๋‚ด๋ถ€์— ์žˆ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ. (React์˜ ์ž…์žฅ์—์„œ)

์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ํ™”๋ฉด์„ ๊ทธ๋ ค์ค˜์•ผํ•˜๋Š”๋ฐ, useState ํ›…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒํƒœ์˜ ๋ณ€ํ™”๊ฐ€ UI์— ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š”๋‹ค.

๋”ฐ๋ผ์„œ useState๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฐ’์ด ๋ณ€ํ™”ํ•˜์˜€์„ ๋•Œ UI์— ๋ฐ˜์˜ํ•ด์ฃผ๋ ค๋ฉด forceUpdate๋ฅผ ์‹œ์ผœ์ค˜์•ผ ํ•œ๋‹ค. class component์—์„œ๋Š” ์กด์žฌํ–ˆ์ง€๋งŒ, function component์—์„œ๋Š” ์ง์ ‘ ๋งŒ๋“ค์–ด์„œ ์“ฐ๋ฉด ๋œ๋‹ค. useState๋ณด๋‹ค useReducer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๊ฐ€๋ณ๋‹ค๋Š” ์˜๊ฒฌ์ด ์žˆ๋‹ค. react-use PR

React๋Š” ์žฌ์กฐ์ • (Reconciliation) ๊ณผ์ •์„ ํ†ตํ•ด ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์™€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•œ๋‹ค. setState๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ useReducer๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

const [, setState] = useState({});
const forceUpdate = () => setState({});

// Custom Hook
function useForceUpdate() {
  const [, setState] = useState({});
  return useCallback(() => setState({}), []);
}

useState๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ , ์ผ๋ฐ˜์ ์ธ ๋ณ€์ˆ˜๋กœ ๊ด€๋ฆฌํ•˜๋ฉด์„œ forceUpdate๋ฅผ ์‹œ์ผœ์ฃผ๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ์ ์ธ External Store์˜ ์•„์ด๋””์–ด๋‹ค. forceUpdate๋ฅผ ์‹œ์ผœ์ค„ ๋•Œ์˜ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์€ state์— ๋ณ€ํ™”๊ฐ€ ์žˆ์–ด์•ผ, ๋ฆฌ์•กํŠธ์—์„œ ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

Business Logic๊ณผ UI๋ฅผ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

React์—์„œ Business Logic์„ ๋ถ„๋ฆฌํ•˜๊ฒŒ ๋˜๋ฉด, React๋Š” Business Logic์ด ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š”์ง€ ์•Œ ํ•„์š” ์—†์ด ๊ฐ€์ ธ๋‹ค ์“ฐ๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๊ณ , UI์™€ ๋ถ„๋ฆฌ๊ฐ€ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— Business Logic์€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ธฐ๊ฐ€ ์‰ฌ์›Œ์ง„๋‹ค.

๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ: ๋‚ด๊ฐ€ ์•Œ๋น ๊ฐ€ ๋ญ์•ผ ๋ผ๋Š” ์‹ ๊ฐ ๋ ˆ์ด์–ด๋ณ„๋กœ ๋ ˆ์ด์–ด๊ฐ€ ๋งก์•„์•ผ ํ•˜๋Š” ์—ญํ• ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

Business Logic์€ ์‰ฝ๊ฒŒ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค. UI๋Š” ์ž์ฃผ ๋ฐ”๋€Œ๋Š”๋ฐ UI์— Business Logic์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์‰ฝ๊ฒŒ ํ„ฐ์ง„๋‹ค.

Last updated