August 14, 2025

๐Ÿ™ˆ ์ถ”์ ๋˜์ง€ ์•Š๋Š” ํด๋ฆญ ์ด๋ฒคํŠธ: UX ํ˜ผ๋ž€๊ณผ ๋ฐ์ดํ„ฐ ๋ถ„์„ ์˜ค๋ฅ˜

JavaScript
React
UX
์—๋Ÿฌ์ฒ˜๋ฆฌ
์ปดํฌ๋„ŒํŠธ
๋น„๋™๊ธฐ์ฒ˜๋ฆฌ
์•„ํ‚คํ…์ฒ˜
์„ฑ๋Šฅ
ํ…Œ์ŠคํŠธ

Summary

ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ œ๋Œ€๋กœ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์œผ๋ฉด UX ์ €ํ•˜, ๋ฐ์ดํ„ฐ ๋ถ„์„ ์˜ค๋ฅ˜, ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜, ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. useEffect ํ›…, ์ด๋ฒคํŠธ ์œ„์ž„, ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ํ…Œ์ŠคํŒ…์„ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Why Wrong?

์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜ ์ถ”์ ์€ UX ๊ฐœ์„ ๊ณผ ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์˜์‚ฌ ๊ฒฐ์ •์— ํ•„์ˆ˜์ ์ด์ง€๋งŒ, ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ œ๋Œ€๋กœ ๊ด€๋ฆฌํ•˜์ง€ ๋ชปํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

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

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

How to Fix?

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ํด๋ฆญ ์ด๋ฒคํŠธ ์ถ”์  ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

Before Code (Bad)

import React, { useState } from 'react';

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

  const handleClick = () => {
    setCount(count + 1);
    // ๋ฌธ์ œ: ์ปดํฌ๋„ŒํŠธ๊ฐ€ unmount๋˜์–ด๋„ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ œ๊ฑฐ๋˜์ง€ ์•Š์Œ
    document.addEventListener('click', () => {
      console.log('Clicked!');
    });
  };

  return (
    <div>
      <button onClick={handleClick}>Click me</button>
      <p>Count: {count}</p>
    </div>
  );
}

export default MyComponent;

After Code (Good)

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

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

  useEffect(() => {
    const handleClick = () => {
      console.log('Clicked!');
    };

    document.addEventListener('click', handleClick);

    // ์ปดํฌ๋„ŒํŠธ๊ฐ€ unmount๋  ๋•Œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ
    return () => {
      document.removeEventListener('click', handleClick);
    };
  }, []); // ๋นˆ ์˜์กด์„ฑ ๋ฐฐ์—ด: ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ/์–ธ๋งˆ์šดํŠธ ์‹œ์—๋งŒ ์‹คํ–‰

  const handleButtonClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <button onClick={handleButtonClick}>Click me</button>
      <p>Count: {count}</p>
    </div>
  );
}

export default MyComponent;