State Pattern - ChoDragon9/posts GitHub Wiki

React Hook, Vue Composition API, Recoil์˜ ๋ฐœ์ƒ ์‹œ๊ธฐ์™€ ์ด์œ ์— ๋Œ€ํ•œ ์ •๋ฆฌ์ž๋ฃŒ๋‹ค.

React Hook

๋ฐœ์ƒ์‹œ๊ธฐ

https://ko.reactjs.org/docs/hooks-intro.html#video-introduction

Hook ์ด๋ž€

https://ko.reactjs.org/docs/hooks-overview.html#state-hook

์—ฌ๊ธฐ์„œ useState๊ฐ€ ๋ฐ”๋กœ Hook ์ž…๋‹ˆ๋‹ค.

import React, { useState } from 'react';

function Example() {
  // "count"๋ผ๋Š” ์ƒˆ ์ƒํƒœ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

https://ko.reactjs.org/docs/hooks-overview.html#but-what-is-a-hook

Hook์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ React state์™€ Lifecycle Features์„ ์—ฐ๋™(hook into) ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜๋‹ค. Hook์€ Class์•ˆ์—์„œ๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋Œ€์‹  Class ์—†์ด React๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

Effect Hook

https://ko.reactjs.org/docs/hooks-overview.html#effect-hook

React ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๊ตฌ๋…ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ DOM์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜๋Š” ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฐ ๋ชจ๋“  ๋™์ž‘์„ side effects ๋˜๋Š” effects๋ผ๊ณ  ํ•œ๋‹ค. ์™œ๋ƒ๋ฉด ์ด๋Ÿฐ ๋™์ž‘์€ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๊ณ , ๋ Œ๋”๋ง ๊ณผ์ •์—์„œ ๊ตฌํ˜„ํ•  ์ˆ˜ ์—†๋Š” ์ž‘์—…์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

useEffect๋Š” ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์ด๋Ÿฐ side effects๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // componentDidMount, componentDidUpdate์™€ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค
  useEffect(() => {
    // ๋ธŒ๋ผ์šฐ์ € API๋ฅผ ์ด์šฉํ•ด ๋ฌธ์„œ์˜ ํƒ€์ดํ‹€์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Hook ์‚ฌ์šฉ ๊ทœ์น™

https://ko.reactjs.org/docs/hooks-overview.html#rules-of-hooks

Hook์€ JS ํ•จ์ˆ˜์ด์ง€๋งŒ, ๋‘ ๊ฐ€์ง€ ๊ทœ์น™์„ ์ค€์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค.

  1. ์ตœ์ƒ์œ„์—์„œ๋งŒ Hook์„ ํ˜ธ์ถœํ•œ๋‹ค.
    • ๋ฐ˜๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ, ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜ ๋‚ด์—์„œ Hook์„ ์‹คํ–‰ํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.
  2. React ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ๋งŒ Hook์„ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.
    • ์ผ๋ฐ˜ JS ํ•จ์ˆ˜์—์„œ๋Š” Hook์„ ํ˜ธ์ถœํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

๋ฐœ์ƒ์ด์œ 

https://ko.reactjs.org/docs/hooks-intro.html#motivation

  • ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์—์„œ ์ƒํƒœ์™€ ๊ด€๋ จ๋œ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
    • React๋Š” ์ปดํฌ๋„ŒํŠธ์— ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ–‰๋™์„ ๋ถ™์ด๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • render props๊ณผ HOCs ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด๋„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋ฉฐ ์ฝ”๋“œ๋ฅผ ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค.
      • ๋‹ค๋ฅธ ์ถ”์ƒํ™” ๋ ˆ์ด์–ด์— ๋‘˜๋Ÿฌ ์Œ“์—ฌ Wrapper Hell์„ ๋ณผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.
  • ๋ณต์žกํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
    • ์œ ์ง€ํ•˜๊ธฐ ํž˜๋“  ์ƒํƒœ์™€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋กœ ์ธํ•ด ๋ฒ„๊ทธ๊ฐ€ ์‰ฝ๊ฒŒ ๋ฐœ์ƒํ•˜๊ณ  ๋ฌด๊ฒฐ์„ฑ์„ ์‰ฝ๊ฒŒ ํ•ด์นœ๋‹ค.
    • ์ƒํƒœ ๊ด€๋ จ ๋กœ์ง์ด ๋ชจ๋“  ๊ณต๊ฐ„์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž‘๊ฒŒ ๋งŒ๋“ค๊ธฐ ํž˜๋“ค๊ณ , ํ…Œ์ŠคํŠธํ•˜๊ธฐ๋„ ์–ด๋ ต๋‹ค.
  • Class๋Š” ์‚ฌ๋žŒ๊ณผ ๊ธฐ๊ณ„๋ฅผ ํ˜ผ๋™์‹œํ‚จ๋‹ค.
    • ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์ฝ”๋“œ ๊ตฌ์„ฑ์„ ์ข€ ๋” ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค.
    • React๋ฅผ ๋ฐฐ์šฐ๋Š” ๋ฐ ํฐ ์ง„์ž…์žฅ๋ฒฝ์ด๋‹ค.
    • JS์˜ this๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š” ์ง€ ์•Œ์•„์•ผ ํ•œ๋‹ค.
    • ์ˆ™๋ จ๋œ React ๊ฐœ๋ฐœ์ž ์‚ฌ์ด์—์„œ๋„ Class ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๊ตฌ๋ณ„ํ•˜๊ณ  ๊ฐ ์š”์†Œ๋ฅผ ์–ธ์ œ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์˜๊ฒฌ์ด ์ผ์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • HMR์—์„œ ๊นจ์ง€๊ธฐ ์‰ฝ๊ณ  ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“ ๋‹ค.

Vue Composition API

๋ฐœ์ƒ์‹œ๊ธฐ

https://vue-composition-api-rfc.netlify.app/#composition-api-rfc

  • 2019.07.10
  • Composition API RFC ์‹œ์ž‘ ๋‚ ์งœ

Composition API ์ด๋ž€

์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๊ฐ€์ ์ธ ํ•จ์ˆ˜๊ธฐ๋ฐ˜ API ์„ธํŠธ๋‹ค. reactive, computed๊ฐ€ Composition API ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
</script>

Composition API ์‚ฌ์šฉ ๊ทœ์น™

  • Composition API์˜ ์ง„์ž…์ ์€ setup ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • Lifecycle Hook์€ setup ํ•จ์ˆ˜์— ๋“ฑ๋กํ•œ๋‹ค.

๋ฐœ์ƒ์ด์œ 

  • ๋กœ์ง ์žฌ์‚ฌ์šฉ & ์ฝ”๋“œ ๊ตฌ์„ฑ
    • ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์ถ”๋ก ํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
    • ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ„์˜ ๋…ผ๋ฆฌ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊นจ๋—ํ•˜๊ณ  ๋น„์šฉ์ด ๋“ค์ง€ ์•Š๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ Vue์—์„œ ์žฌ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋” ์ข‹์€ ํƒ€์ž… ์ถ”๋ก 
    • Vue2 API๋Š” ๋‹จ์ˆœํžˆ ํƒ€์ž… ์ถ”๋ก ์„ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋˜์ง€ ์•Š์•„ TS์™€ ์ž˜ ์ž‘๋™ํ•˜๋„๋ก ๋งŒ๋“ค ๋•Œ ๋งŽ์€ ๋ณต์žก์„ฑ์„ ๋งŒ๋“ ๋‹ค.
      • Vue2 API๋Š” this ์ปจํ…์ŠคํŠธ๋ฅผ ์˜์กดํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— TS ํ†ตํ•ฉ์ด ์–ด๋ ต๋‹ค.
      • Vue2์˜ this๋Š” JS ๋ณด๋‹ค ๋งˆ์ˆ ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.
      • ์˜ˆ๋ฅผ ๋“ค์–ด methods ์•„๋ž˜์— ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜์˜ this๋Š” methods ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์•„๋‹Œ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
    • Class API๋กœ ์ œ๊ณตํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ์œผ๋‚˜ Decorator๋ฅผ ์˜์กดํ•ด์•ผ ํ•จ์œผ๋กœ Vue3์˜ ๊ธฐ๋ฐ˜์„ ์„ธ์šฐ๋Š” ๋ฐ, ์œ„ํ—˜ํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค.
    • ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์นœ์ˆ™ํ•œ ์ผ๋ฐ˜ ๋ณ€์ˆ˜์™€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ๋ฉ”๋‰ด์–ผ ํƒ€์ž… ํžŒํŠธ๊ฐ€ ๊ฑฐ์˜ ํ•„์š”์—†๋Š” ํƒ€์ž… ์ถ”๋ก ์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ๋‹ค.

Recoil

๋ฐœ์ƒ์‹œ๊ธฐ

Recoil ์ด๋ž€

https://recoiljs.org/docs/introduction/core-concepts

Recoil์€ ์ƒํƒœ๋จธ์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค. Atoms๊ณผ Selectors๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

Atoms

const fontSizeState = atom({
  key: 'fontSizeState',
  default: 14,
});

function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  return (
    <button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
      Click to Enlarge
    </button>
  );
}

function Text() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  return <p style={{fontSize}}>This text will increase in size too.</p>;
}

Selectors

const fontSizeLabelState = selector({
  key: 'fontSizeLabelState',
  get: ({get}) => {
    const fontSize = get(fontSizeState);
    const unit = 'px';

    return `${fontSize}${unit}`;
  },
});

function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  const fontSizeLabel = useRecoilValue(fontSizeLabelState);

  return (
    <>
      <div>Current font size: ${fontSizeLabel}</div>

      <button onClick={() => setFontSize(fontSize + 1)} style={{fontSize}}>
        Click to Enlarge
      </button>
    </>
  );
}

Recoil ์‚ฌ์šฉ ๊ทœ์น™

  • key๋Š” ๊ณ ์œ ํ•œ ํ‚ค๋ฅผ ํ• ๋‹นํ•œ๋‹ค.
    • ๋””๋ฒ„๊น…๊ณผ ์˜์†์„ฑ์— ์ด์ ์„ ์œ„ํ•จ์ด๋‹ค.
  • Selectors๋Š” ์ˆœ์ˆ˜ํ•จ์ˆ˜๋กœ ์ •์˜ํ•œ๋‹ค.

๋ฐœ์ƒ์ด์œ 

  • React ์ปดํฌ๋„ŒํŠธ๋Š” ๊ณตํ†ต ์กฐ์ƒ์„ ํ†ตํ•ด ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์—๋Š” ๊ฑฐ๋Œ€ํ•œ ํŠธ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Context๋Š” ๊ฐ๊ฐ ์ž์ฒด Consumer๊ฐ€ ์žˆ๋Š” ๋ฌดํ•œํ•œ ์„ธํŠธ๋ฅผ ๊ฐ€์ง€๋Š” ๊ฒŒ ์•„๋‹Œ ๋‹จ์ผ ๊ฐ’๋งŒ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํŠธ๋ฆฌ์˜ ์žŽ๊ณผ ๊ผญ๋Œ€๊ธฐ์˜ ์ฝ”๋“œ๋ถ„ํ• ์„ ํž˜๋“ค๊ฒŒ ํ•œ๋‹ค.

๋

๊ฐ™์ด ๋ณผ๋งŒํ•œ ์ž๋ฃŒ

โš ๏ธ **GitHub.com Fallback** โš ๏ธ