Wanted Challenge_React์˜ Hooks-useState, useContext, useEffect

์ •์œค์ˆ™ยท2024๋…„ 4์›” 16์ผ
0

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
192/192
post-thumbnail

๐Ÿ“’ ์˜ค๋Š˜์˜ ๊ณต๋ถ€

1. React์˜ Hooks

Wanted Frontend Challenge - React ๊ฐ•์˜ ๋‚ด์šฉ ์ •๋ฆฌ_2-1

1. React์˜ Hooks

  • React์˜ Hooks : useState, useContext, useEffect

  • Hook์˜ ์žฅ์ 

    • ๋กœ์ง์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ, ๊ด€๋ฆฌ๊ฐ€ ์‰ฝ๋‹ค.
      -> Hook์€ ํ•จ์ˆ˜ ์•ˆ์—์„œ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ƒˆ๋กœ์šด Hook ์ƒ์„ฑ ๊ฐ€๋Šฅ
    • ๋กœ์ง์„ ํ•œ ๊ณณ์— ๋ชจ์„ ์ˆ˜ ์žˆ์–ด์„œ ๊ฐ€๋…์„ฑ์ด ์ข‹์Œ
  • Hook ์‚ฌ์šฉ ์‹œ ๊ทœ์น™

    • ์ปดํฌ๋„ŒํŠธ ์ตœ์ƒ์œ„์—์„œ๋งŒ Hook ์‚ฌ์šฉํ•˜๊ธฐ
      -> ๋ฐ˜๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ ํ•จ ์ˆ˜ ์•ˆ์—์„œ ์‚ฌ์šฉ ๋ถˆ๊ฐ€
    • Hook์€ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • React ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ(JS์•ˆ์—์„œ ์‚ฌ์šฉX) => jsx ํŒŒ์ผ ๋‚ด์—์„œ ์‚ฌ์šฉ

useSate

  • ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒํƒœ ๋ณ€์ˆ˜์™€ ํ•ด๋‹น ๋ณ€์ˆ˜๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” React์˜ Hook
  • state = ์ƒํƒœ = ๋ณ€์ˆ˜
  • setState = state๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜
  • initialStaet = ์ดˆ๊ธฐ๊ฐ’

  • useSate๊ฐ€ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•
    • ์›น์ด ๋กœ๋”ฉ๋˜๋ฉด์„œ Counter ์ปดํฌ๋„ŒํŠธ ํ˜ธ์ถœ
    • ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ 0์„ ์ „๋‹ฌํ•˜๋ฉฐ useState ํ˜ธ์ถœ
    • handleClick ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋ฉฐ ์ƒํƒœ๋ณ€๊ฒฝ ํ•จ์ˆ˜(setCount) ํ˜ธ์ถœ
    • Rerender ๋ฐœ์ƒ
    • Counter ์ปดํฌ๋„ŒํŠธ ๋‘ ๋ฒˆ์งธ ์‹คํ–‰
    • ์ด์ „ ์ƒํƒœ๋ณ€๊ฒฝ ํ•จ์ˆ˜(setCount)๋กœ ์ธํ•ด count๊ฐ’์ด 1์ด ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐ๊ฐ’(0) ํ• ๋‹น๋ฌธ ๋ฌด์‹œ

useContext

  • useContext๋Š” Context API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „์—ญ ์ƒํƒœ๋ฅผ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์†์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” React์˜ Hook

    • Context API๋Š” React์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์—ญ์œผ๋กœ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ฉฐ, ์ฃผ๋กœ props drilling ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

    • Context API์—์„œ state ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด, Provider๋กœ ๊ฐ์‹ผ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๋ฆฌ๋ Œ๋”๋ง

    • ex. ํ…Œ๋งˆ ๋ฐ์ดํ„ฐ(๋‹คํฌ, ๋ผ์ดํŠธ) / ์ธ์ฆ ๋œ ์‚ฌ์šฉ์ž ํ™•์ธ(๋กœ๊ทธ์ธ) / ์ด ์™ธ์— ์ž์ฃผ ์—…๋ฐ์ดํŠธํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๋ฐ์ดํ„ฐ


      ๐Ÿ’ก Props Drilling์ด๋ž€?

      Prop drilling์€ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ณผ์ •์„ ์„ค๋ช…ํ•˜๋Š” ์šฉ์–ด.
      React์—์„œ๋Š” ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ์ดํ„ฐ(์ƒํƒœ)๋ฅผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ์ค‘๊ฐ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด ํ”„๋กœํผํ‹ฐ๋ฅผ ๋‚ด๋ ค์ฃผ๊ฒŒ ๋œ๋‹ค.
      ์ค‘๊ฐ„ ์ปดํฌ๋„ŒํŠธ ์ž…์žฅ์—์„œ๋Š” ํƒ€๊ฒŸ์ธ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ฐ›๋Š” ์…ˆ์ด๋‹ค.
      ๋งŒ์•ฝ 10๊ฐœ, 20๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฑฐ์ณ์•ผํ•œ๋‹ค๋ฉด?
      -> ๊ฐ€์žฅ ๋จผ์ € Props๊ฐ€ ์–ด๋””์„œ ์˜จ๊ฒƒ์ธ์ง€ ์ถ”์ ์ด ์–ด๋ ค์›€ -> ์œ ์ง€๋ณด์ˆ˜ ๋น„ํšจ์œจ


  • ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

    • createContext๋กœ context ์ƒ์„ฑ

    • ๋Œ€์ƒ ์ปดํฌ๋„ŒํŠธ(<Form />)์— ๊ฐ’์„ ๋‚ด๋ ค์ฃผ๊ธฐ ์œ„ํ•ด์„œ Provider๋กœ
      ๋Œ€์ƒ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ผ๋‹ค. -> Provider ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ชจ๋‘ ์ ‘๊ทผ ๊ฐ€๋Šฅ

    • Provider์˜ value ์†์„ฑ์œผ๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ

      import { createContext, useContext } from 'react';
      
      const ThemeContext = createContext(null);
      
      export default function MyApp() {
        return (
          <ThemeContext.Provider value="dark">
            <Form />
          </ThemeContext.Provider>
        )
      }
  • ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ useContext๋ฅผ ์ด์šฉํ•ด context์˜ value(dark)์— ์ ‘๊ทผ ๊ฐ€๋Šฅ
    const theme = useContext(ThemeContext)

    • ์œ„์˜ ๋ณ€์ˆ˜๋ฅผ className์œผ๋กœ ํ™œ์šฉํ•˜์—ฌ CSS ๋ณ€๊ฒฝ
      const className = 'panel-' + theme

      function Form() {
       return (
         <Panel title="Welcome">
           <Button>Sign up</Button>
           <Button>Log in</Button>
         </Panel>
       );
      }
      
      function Panel({ title, children }) {
       const theme = useContext(ThemeContext);
       const className = 'panel-' + theme;
       return (
         <section className={className}>
           <h1>{title}</h1>
           {children}
         </section>
       )
      }
      
      function Button({ children }) {
       const theme = useContext(ThemeContext);
       const className = 'button-' + theme;
       return (
         <button className={className}>
           {children}
         </button>
       );
      }
  • ๊ด€๋ จ CSS ์˜ˆ์‹œ

    .panel-light {
      background-color: #f4f4f4;
      color: #333;
    }
    
    .panel-dark {
      background-color: #222;
      color: #fff;
    }
    
    .button-light {
      background-color: #fff;
      color: #333;
      border: 1px solid #333;
    }
    
    .button-dark {
      background-color: #333;
      color: #fff;
      border: 1px solid #fff;
    }
  • ๊ฒฐ๊ณผ๋ฌผ
    • context์˜ value(light / dark)๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด Provider์˜ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๋ชจ๋‘ ๋ฆฌ๋ Œ๋”๋ง๋˜๋ฉฐ css๊ฐ€ ๋ณ€๊ฒฝ ๋œ๋‹ค.

2. useEffect๋ฅผ ํ™œ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ

  • useEffect๋Š” ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” React์˜ Hook
    useEffect(callback[, dependencies])

    • ์ฒซ๋ฒˆ์งธ ์ธ์ž๋กœ๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ›๊ณ , ๋‘๋ฒˆ์งธ ์ธ์ž๋กœ๋Š” ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ๋ฐ›๋Š”๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ์˜ ์ƒ๋ช…์ฃผ๊ธฐ

  • mount

    • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ์œผ๋กœ ํ™”๋ฉด์— ํ‘œ์‹œ๋  ๋•Œ(์ตœ์ดˆ๋กœ ์ง„ํ–‰๋˜๋Š” ๋ Œ๋”๋ง)
    • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋œ ์ดํ›„ useEffect์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ „๋‹ฌ๋œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์‹คํ–‰
  • update

    • state๋‚˜ props๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ
    • ์ด ๋•Œ, useEffect๋Š” ๋‘ ๋ฒˆ์งธ ์ธ์ž์— ๋“ค์–ด์žˆ๋Š” ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ์ฒดํฌ
      => ์˜์กด์„ฑ ๋ฐฐ์—ด๋กœ ์ „๋‹ฌ๋œ ๊ฐ’ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์—…๋ฐ์ดํŠธ๋œ ๊ฒฝ์šฐ, ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ „๋‹ฌ๋œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰
      => ์˜์กด์„ฑ ๋ฐฐ์—ด์— ์—…๋ฐ์ดํŠธ ๋œ ๊ฐ’์ด ์—†๊ฑฐ๋‚˜ ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋น„์–ด์žˆ๋‹ค๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค
    • ๋งŒ์•ฝ useEffect ๋‚ด์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋กœ ์ธํ•ด state๋‚˜ props๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด ๋ฆฌ๋žœ๋”๋ง ๋ฐœ์ƒ
  • unmout

    • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์—์„œ ์‚ฌ๋ผ์ง€๋Š” ๊ฒƒ
    • useEffect ๋‚ด์˜ return ๋ฌธ์„ ํ†ตํ•ด ์ •๋ฆฌ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰
    import React, { useEffect } from 'react';
    
    function TimerComponent() {
      useEffect(() => {
        const timerId = setInterval(() => {
          console.log('Timer tick');
        }, 1000);
    
        return () => {
          clearInterval(timerId); // ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋  ๋•Œ ํƒ€์ด๋จธ๋ฅผ ์ข…๋ฃŒ
        };
      }, []); // ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋นˆ ๋ฐฐ์—ด์ด๋ฏ€๋กœ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋  ๋•Œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰
    
      return (
        <div>
          Timer Component
        </div>
      );
    }
    
    export default TimerComponent;
    

3. ๊ด€๋ จ ์งˆ๋ฌธ์— ๋‹ต๋ณ€ํ•˜๊ธฐ

mount์™€ rendering์˜ ์ฐจ์ด

  • mount๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ์œผ๋กœ ๋ Œ๋”๋ง๋˜์–ด ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ rendering์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์— ๋ Œ๋”๋ง๋˜๋Š” ๊ณผ์ • ์ž์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • mount๋Š” rendering์˜ ์ผ๋ถ€๋ถ„์ด๋ฉฐ, mount๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ DOM์— ์ถ”๊ฐ€๋  ๋•Œ๋งŒ ๋ฐœ์ƒํ•˜์ง€๋งŒ, rendering์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚  ๋•Œ๋งˆ๋‹ค ๋ฐœ์ƒํ•œ๋‹ค.

Props Drilling์˜ ๊ฐœ๋…๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

  • Props Drilling์€ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฑฐ์ณ ์ „๋‹ฌ๋˜๋Š” ์ƒํ™ฉ์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌ๋˜์–ด์•ผ ํ•˜์ง€๋งŒ, ์ค‘๊ฐ„์— ์žˆ๋Š” ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์— ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Context API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ „์—ญ์œผ๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ค‘๊ฐ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฑฐ์น  ํ•„์š”์—†์ด ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ง์ ‘ Context๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ

profile
ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€