July 15, 2025

๐Ÿ—‘๏ธ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋ˆ„์ˆ˜: ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์™€ ์„ฑ๋Šฅ ์ €ํ•˜์˜ ์ฃผ๋ฒ”

JavaScript
์„ฑ๋Šฅ
์—๋Ÿฌ์ฒ˜๋ฆฌ
์›นํ‘œ์ค€

Summary

๋” ์ด์ƒ ํ•„์š” ์—†๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ œ๊ฑฐํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์™€ ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค. addEventListener์™€ removeEventListener๋ฅผ ํ•ญ์ƒ ์Œ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ , ํŠนํžˆ React์—์„œ๋Š” useEffect์˜ ํด๋ฆฐ์—… ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Why Wrong?

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

How to Fix?

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

Before Code (Bad)

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

function ResizableBox() {
  const [width, setWidth] = useState(window.innerWidth);

  // โŒ ๋ฌธ์ œ: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋  ๋•Œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ œ๊ฑฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  // ์ด ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๊ฐ€ DOM์—์„œ ์‚ฌ๋ผ์ ธ๋„, window resize ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋Š” ๊ณ„์† ๋‚จ์•„์žˆ์Šต๋‹ˆ๋‹ค.
  useEffect(() => {
    const handleResize = () => {
      setWidth(window.innerWidth);
      console.log('Window resized!');
    };

    window.addEventListener('resize', handleResize);
    // return () => window.removeEventListener('resize', handleResize); // ์ด ํด๋ฆฐ์—… ๋กœ์ง์ด ๋ˆ„๋ฝ๋จ
  }, []); // ๋นˆ ์˜์กด์„ฑ ๋ฐฐ์—ด๋กœ ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜์ง€๋งŒ, ์–ธ๋งˆ์šดํŠธ ์‹œ ํด๋ฆฐ์—…์ด ์—†์Œ

  return (
    <div style={{ border: '1px solid black', padding: '20px', margin: '20px' }}>
      <h1>ํ˜„์žฌ ์ฐฝ ๋„ˆ๋น„: {width}px</h1>
      <p>์ฐฝ ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•ด๋ณด์„ธ์š”.</p>
    </div>
  );
}

export default ResizableBox;

// ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ๋งˆ์šดํŠธํ•˜๊ณ  ์–ธ๋งˆ์šดํŠธํ•˜๋ฉด,
// `handleResize` ํ•จ์ˆ˜๊ฐ€ ๊ณ„์†ํ•ด์„œ ๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์•„์žˆ๊ณ ,
// window resize ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ ์ด์ „์— ๋งˆ์šดํŠธ๋˜์—ˆ๋˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์˜ handleResize ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์–ด
// ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๋ฅผ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค.

After Code (Good)

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

function ResizableBox() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => {
      setWidth(window.innerWidth);
      console.log('Window resized!');
    };

    // โœ… ์˜ฌ๋ฐ”๋ฅธ ํ•ด๊ฒฐ์ฑ…: ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
    window.addEventListener('resize', handleResize);

    // useEffect์˜ ํด๋ฆฐ์—… ํ•จ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋˜๊ฑฐ๋‚˜
    // ๋‹ค์Œ ๋ Œ๋”๋ง ์‹œ ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋ณ€๊ฒฝ๋˜๊ธฐ ์ „์— ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []); // ๋นˆ ์˜์กด์„ฑ ๋ฐฐ์—ด๋กœ ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ ๋ฐ ์–ธ๋งˆ์šดํŠธ ์‹œ ํด๋ฆฐ์—… ๋ณด์žฅ

  return (
    <div style={{ border: '1px solid black', padding: '20px', margin: '20px' }}>
      <h1>ํ˜„์žฌ ์ฐฝ ๋„ˆ๋น„: {width}px</h1>
      <p>์ฐฝ ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•ด๋ณด์„ธ์š”.</p>
    </div>
  );
}

export default ResizableBox;

// ์ด์ œ ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งˆ์šดํŠธ/์–ธ๋งˆ์šดํŠธํ•ด๋„
// ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์—†์ด ๊น”๋”ํ•˜๊ฒŒ ๊ด€๋ฆฌ๋˜๋ฉฐ, ๋ถˆํ•„์š”ํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋„ ๋ฐฉ์ง€๋ฉ๋‹ˆ๋‹ค.