๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Lect & Tip/React by GPT

useState์™€ useEffect, ๋ฆฌ์•กํŠธ Hooks๋ฅผ ํ™œ์šฉํ•œ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ์ปดํฌ๋„ŒํŠธ ์„ค๊ณ„

by st๊ณต๊ฐ„ 2025. 5. 30.
๋ฐ˜์‘ํ˜•

useState์™€ useEffect, ๋ฆฌ์•กํŠธ Hooks๋ฅผ ํ™œ์šฉํ•œ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ์ปดํฌ๋„ŒํŠธ ์„ค๊ณ„

๋ฆฌ์•กํŠธ 16.8 ๋ฒ„์ „ ์ดํ›„ ๋“ฑ์žฅํ•œ Hooks๋Š” ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์—ฌ, ์ฝ”๋“œ์˜ ๊ฐ„๊ฒฐ์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” useState, useEffect, useContext ๋“ฑ ๊ธฐ๋ณธ ์ œ๊ณต๋˜๋Š” ๋‹ค์–‘ํ•œ ํ›…๋“ค์„ ํ™œ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐ ๋กœ์ง ๋ถ„๋ฆฌ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ž์„ธํžˆ ๋‹ค๋ฃจ๊ณ , ์ปค์Šคํ…€ ํ›… ์ œ์ž‘ ์‚ฌ๋ก€๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๋Š” ์ „๋žต์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ Hooks์˜ ๊ธฐ๋ณธ ์›๋ฆฌ์™€ ์žฅ์ 

๋ฆฌ์•กํŠธ Hooks๋Š” ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ(์ƒํƒœ ๊ด€๋ฆฌ, ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์„œ๋“œ ๋Œ€์ฒด)์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Hooks๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง€๋ฉฐ ํ…Œ์ŠคํŠธ์™€ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•ด์ง‘๋‹ˆ๋‹ค.

ํŠนํžˆ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ์—์„œ Hooks๋Š” ๊ธฐ์กด ๋ฐฉ์‹๋ณด๋‹ค ๋งŽ์€ ์žฅ์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • ์ƒํƒœ ๊ด€๋ฆฌ์˜ ๋‹จ์ˆœํ™”: useState๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์˜ this.state์™€ this.setState๋ฅผ ๋Œ€์ฒดํ•˜์—ฌ ๋” ์ง๊ด€์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์ œ์–ด: useEffect๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ์˜ ๋งˆ์šดํŠธ, ์—…๋ฐ์ดํŠธ, ์–ธ๋งˆ์šดํŠธ ์‹œ์ ์— ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…(๋ฐ์ดํ„ฐ ํŒจ์นญ, ์ด๋ฒคํŠธ ๋“ฑ๋ก ๋“ฑ)์„ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜ ๋‚ด์—์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ปจํ…์ŠคํŠธ ํ™œ์šฉ: useContext๋ฅผ ํ†ตํ•ด ์ „์—ญ ์ƒํƒœ๋‚˜ ์„ค์ •์„ ์‰ฝ๊ฒŒ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์–ด, ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด ๊ฐ„ํŽธํ•ด์ง‘๋‹ˆ๋‹ค.
  • ๋กœ์ง ๋ถ„๋ฆฌ ๋ฐ ์žฌ์‚ฌ์šฉ: ์ปค์Šคํ…€ ํ›…(Custom Hooks)์„ ๋งŒ๋“ค์–ด ๊ณตํ†ต ๋กœ์ง์„ ์บก์Аํ™”ํ•จ์œผ๋กœ์จ, ์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ด๊ณ  ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์†์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

useState์™€ ์ปดํฌ๋„ŒํŠธ ์ƒํƒœ ๊ด€๋ฆฌ

useState ํ›…์€ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ด ๋˜๋Š” ํ›…์ž…๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์ œ๋Š” ๊ฐ„๋‹จํ•œ ์นด์šดํ„ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค.

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);

  return (
    <div style={{ textAlign: 'center', margin: '20px' }}>
      <h2>ํ˜„์žฌ ์นด์šดํŠธ: {count}</h2>
      <button onClick={decrement} style={{ marginRight: '10px' }}>๊ฐ์†Œ</button>
      <button onClick={increment}>์ฆ๊ฐ€</button>
    </div>
  );
};

export default Counter;

์œ„ ์˜ˆ์ œ๋Š” useState๋ฅผ ํ†ตํ•ด count๋ผ๋Š” ์ƒํƒœ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” setCount ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ ์นด์šดํ„ฐ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ๋ชจ์Šต์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ƒํƒœ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ์ ์ด Hooks์˜ ํฐ ์žฅ์ ์ž…๋‹ˆ๋‹ค.

useEffect๋ฅผ ํ™œ์šฉํ•œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๊ด€๋ฆฌ

useEffect ํ›…์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋œ ํ›„ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜๋กœ, ๋ฐ์ดํ„ฐ ํŒจ์นญ, ๊ตฌ๋…(subscription), DOM ๋ณ€๊ฒฝ ๋“ฑ ๋‹ค์–‘ํ•œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋Š” ๋ฐ์ดํ„ฐ ํŒจ์นญ์„ ์œ„ํ•œ useEffect ์‚ฌ์šฉ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค.

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

const DataFetcher = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // API ํ˜ธ์ถœ ๋ฐ ๋ฐ์ดํ„ฐ ํŒจ์นญ
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(json => {
        setData(json.slice(0, 5)); // ์˜ˆ์‹œ๋กœ ์ƒ์œ„ 5๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋งŒ ์‚ฌ์šฉ
        setLoading(false);
      })
      .catch(error => {
        console.error('๋ฐ์ดํ„ฐ ํŒจ์นญ ์—๋Ÿฌ:', error);
        setLoading(false);
      });
  }, []); // ๋นˆ ๋ฐฐ์—ด์„ ์˜์กด์„ฑ ๋ฐฐ์—ด๋กœ ์„ค์ •ํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰

  return (
    <div style={{ padding: '20px' }}>
      <h2>๋ฐ์ดํ„ฐ ํŒจ์นญ ์˜ˆ์ œ</h2>
      {loading ? (
        <p>๋กœ๋”ฉ ์ค‘...</p>
      ) : (
        <ul>
          {data.map(item => (
            <li key={item.id}>{item.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default DataFetcher;

์œ„ ์ฝ”๋“œ์—์„œ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋งˆ์šดํŠธ๋  ๋•Œ API ํ˜ธ์ถœ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์นญํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. useEffect์˜ ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ๋นˆ ๋ฐฐ์—ด๋กœ ์„ค์ •ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ์—๋งŒ ์‹คํ–‰๋˜๋„๋ก ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

useContext๋ฅผ ํ†ตํ•œ ์ „์—ญ ์ƒํƒœ ๊ณต์œ 

๋ฆฌ์•กํŠธ์—์„œ ์ „์—ญ ์ƒํƒœ๋‚˜ ๊ณตํ†ต ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— ๊ณต์œ ํ•  ๋•Œ Context API๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. useContext ํ›…์„ ์‚ฌ์šฉํ•˜๋ฉด Context์˜ ๊ฐ’์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ์–ด, ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ํ›จ์”ฌ ์ˆ˜์›”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ์˜ˆ์ œ๋Š” ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์ „์—ญ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” Context๋ฅผ ์„ค์ •ํ•˜๊ณ , ์ด๋ฅผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค.

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

// ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด์„ Context ์ƒ์„ฑ
const AuthContext = React.createContext();

const AuthProvider = ({ children }) => {
  const [user, setUser] = useState({ name: 'ํ™๊ธธ๋™', isAuthenticated: true });

  return (
    <AuthContext.Provider value={{ user, setUser }}>
      {children}
    </AuthContext.Provider>
  );
};

const UserProfile = () => {
  const { user } = useContext(AuthContext);

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', marginTop: '20px' }}>
      <h2>์‚ฌ์šฉ์ž ํ”„๋กœํ•„</h2>
      <p>์ด๋ฆ„: {user.name}</p>
      <p>์ธ์ฆ ์ƒํƒœ: {user.isAuthenticated ? '์ธ์ฆ๋จ' : '๋ฏธ์ธ์ฆ'}</p>
    </div>
  );
};

const App = () => {
  return (
    <AuthProvider>
      <div style={{ maxWidth: '600px', margin: '0 auto' }}>
        <h2>๋ฆฌ์•กํŠธ Hooks๋ฅผ ํ™œ์šฉํ•œ ์ƒํƒœ ๊ด€๋ฆฌ</h2>
        <UserProfile />
      </div>
    </AuthProvider>
  );
};

export default App;

์œ„ ์˜ˆ์ œ๋Š” AuthContext๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ „์—ญ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์ธ UserProfile์—์„œ useContext๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ„ํŽธํ•˜๊ฒŒ ์ธ์ฆ ์ •๋ณด๋ฅผ ๋ฐ›์•„ ์ถœ๋ ฅํ•˜๋Š” ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค.

์ปค์Šคํ…€ ํ›…(Custom Hooks) ์ œ์ž‘๊ณผ ํ™œ์šฉ

์ปค์Šคํ…€ ํ›…์€ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋กœ์ง์„ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋กœ ์บก์Аํ™”ํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์œˆ๋„์šฐ ํฌ๊ธฐ๋ฅผ ์ถ”์ ํ•˜๋Š” ๋กœ์ง์„ ์ปค์Šคํ…€ ํ›…์œผ๋กœ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import { useState, useEffect } from 'react';

const useWindowSize = () => {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    const handleResize = () => {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    // ์œˆ๋„์šฐ ๋ฆฌ์‚ฌ์ด์ฆˆ ์ด๋ฒคํŠธ ๋“ฑ๋ก
    window.addEventListener('resize', handleResize);

    // ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ ์ด๋ฒคํŠธ ์ œ๊ฑฐ
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowSize;
};

export default useWindowSize;

์ด์ œ ์ด ์ปค์Šคํ…€ ํ›…์„ ํ™œ์šฉํ•˜์—ฌ ํ˜„์žฌ ์œˆ๋„์šฐ ํฌ๊ธฐ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import React from 'react';
import useWindowSize from './useWindowSize';

const WindowSizeDisplay = () => {
  const { width, height } = useWindowSize();

  return (
    <div style={{ padding: '20px', border: '1px solid #007acc', marginTop: '20px' }}>
      <h2>ํ˜„์žฌ ์œˆ๋„์šฐ ํฌ๊ธฐ</h2>
      <p>๋„ˆ๋น„: {width}px</p>
      <p>๋†’์ด: {height}px</p>
    </div>
  );
};

export default WindowSizeDisplay;

์ด์ฒ˜๋Ÿผ ์ปค์Šคํ…€ ํ›…์€ ์ปดํฌ๋„ŒํŠธ์— ๋ณต์žกํ•œ ๋กœ์ง์„ ์ฃผ์ž…ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋กœ์ง์„ ๋ณ„๋„์˜ ํ›…์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋ฉด, ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

๋ณตํ•ฉ ์ปดํฌ๋„ŒํŠธ์—์„œ์˜ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ๋กœ์ง ๋ถ„๋ฆฌ ์ „๋žต

๋Œ€๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ณตํ•ฉ์ ์œผ๋กœ ์—ฐ๋™๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์ƒํƒœ ๊ด€๋ฆฌ์™€ ๋กœ์ง ๋ถ„๋ฆฌ๊ฐ€ ๋”์šฑ ์ค‘์š”ํ•ด์ง‘๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ด๋ฅผ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ์ „๋žต์ž…๋‹ˆ๋‹ค.

  1. ๋กœ์ง ๋ถ„๋ฆฌ์™€ ์žฌ์‚ฌ์šฉ: ๊ณตํ†ต ๊ธฐ๋Šฅ์€ ์ปค์Šคํ…€ ํ›…์ด๋‚˜ ๋ณ„๋„์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ, ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ปจํ…์ŠคํŠธ์™€ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ: useContext์™€ ํ•จ๊ป˜ Redux, MobX, Recoil ๋“ฑ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋„์ž…ํ•˜๋ฉด, ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ์ƒํƒœ ๊ณต์œ  ๋ฐ ์—…๋ฐ์ดํŠธ๊ฐ€ ์ˆ˜์›”ํ•ด์ง‘๋‹ˆ๋‹ค.
  3. ๋ชจ๋“ˆํ™”๋œ ์ปดํฌ๋„ŒํŠธ ์„ค๊ณ„: ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ์ž‘์€ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์–ด, ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(Single Responsibility Principle)์„ ๋”ฐ๋ฅด๋„๋ก ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ•œ ์ปดํฌ๋„ŒํŠธ ๋‚ด์˜ ์ƒํƒœ์™€ ๋กœ์ง์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  4. ํ…Œ์ŠคํŠธ์™€ ๋””๋ฒ„๊น…: ์ปค์Šคํ…€ ํ›…๊ณผ ์ปดํฌ๋„ŒํŠธ ๋ณ„๋กœ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ, ๋กœ์ง ๋ณ€๊ฒฝ ์‹œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋ฅผ ๋ฏธ์—ฐ์— ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Jest, React Testing Library ๋“ฑ์„ ํ™œ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๋†’์ด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

๋ฆฌ์•กํŠธ Hooks๋ฅผ ํ™œ์šฉํ•œ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ์ปดํฌ๋„ŒํŠธ ์„ค๊ณ„๋Š” ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์˜ ์žฅ์ ์„ ๊ทน๋Œ€ํ™”ํ•˜์—ฌ, ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. useState, useEffect, useContext์™€ ๊ฐ™์€ ๊ธฐ๋ณธ ํ›…์„ ํ†ตํ•ด ๊ฐœ๋ณ„ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ์™€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ์ปค์Šคํ…€ ํ›…์„ ํ†ตํ•ด ๊ณตํ†ต ๋กœ์ง์„ ์บก์Аํ™”ํ•จ์œผ๋กœ์จ, ๋ณต์žกํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋„ ์œ ์ง€๋ณด์ˆ˜์™€ ํ™•์žฅ์„ฑ์ด ๋›ฐ์–ด๋‚œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์•ž์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ, ์œ„์—์„œ ์†Œ๊ฐœํ•œ Hooks ์‚ฌ์šฉ๋ฒ•๊ณผ ์ปค์Šคํ…€ ํ›… ์ œ์ž‘ ์‚ฌ๋ก€๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋ณด๋‹ค ๊น”๋”ํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์šด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜๊ณผ ๊ฐœ๋ฐœ ํšจ์œจ์„ฑ์„ ๋™์‹œ์— ๋†’์ด๋Š” ํ˜์‹ ์ ์ธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€