<StrictMode>๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ ์ค‘์— ์ปดํฌ๋„ŒํŠธ์—์„œ ์ผ๋ฐ˜์ ์ธ ๋ฒ„๊ทธ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

<StrictMode>
<App />
</StrictMode>

๋ ˆํผ๋Ÿฐ์Šค

<StrictMode>

์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ๋‚ด๋ถ€์—์„œ ์ถ”๊ฐ€์ ์ธ ๊ฐœ๋ฐœ ๋™์ž‘ ๋ฐ ๊ฒฝ๊ณ ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์œ„ํ•ด StrictMode๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<App />
</StrictMode>
);

์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Strict Mode๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐœ๋ฐœ ์ „์šฉ ๋™์ž‘์„ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.

Props

StrictMode๋Š” Props๋ฅผ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฃผ์˜ ์‚ฌํ•ญ

  • <StrictMode>๋กœ ๋ž˜ํ•‘๋œ ํŠธ๋ฆฌ ๋‚ด์—์„œ Strict Mode๋ฅผ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด <StrictMode> ๋‚ด๋ถ€์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฒ€์‚ฌ๋˜์—ˆ์Œ์„ ํ™•์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œํ’ˆ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋‘ ํŒ€์ด ๊ฒ€์‚ฌ๊ฐ€ ๊ฐ€์น˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•ด ์˜๊ฒฌ์ด ๊ฐˆ๋ฆฌ๋Š” ๊ฒฝ์šฐ, ํ•ฉ์˜์— ๋„๋‹ฌํ•˜๊ฑฐ๋‚˜ <StrictMode>๋ฅผ ํŠธ๋ฆฌ์—์„œ ํ•˜๋‹จ์œผ๋กœ ์˜ฎ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•

์ „์ฒด ์•ฑ์— ๋Œ€ํ•ด Strict Mode ํ™œ์„ฑํ™”

Strict Mode๋Š” <StrictMode> ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์— ๋Œ€ํ•ด ์ถ”๊ฐ€์ ์ธ ๊ฐœ๋ฐœ ์ „์šฉ ๊ฒ€์‚ฌ๋ฅผ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒ€์‚ฌ๋Š” ๊ฐœ๋ฐœ ํ”„๋กœ์„ธ์Šค ์ดˆ๊ธฐ์— ์ปดํฌ๋„ŒํŠธ์—์„œ ์ผ๋ฐ˜์ ์ธ ๋ฒ„๊ทธ๋ฅผ ์ฐพ๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

์ „์ฒด ์•ฑ์— ๋Œ€ํ•œ Strict Mode๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด ๋ Œ๋”๋งํ•  ๋•Œ ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ <StrictMode>๋กœ ๋ž˜ํ•‘ํ•˜์„ธ์š”.

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<App />
</StrictMode>
);

์ „์ฒด ์•ฑ์„ (ํŠนํžˆ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ์•ฑ์˜ ๊ฒฝ์šฐ) Strict Mode๋กœ ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. createRoot๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, Strict Mode๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

Strict Mode ๊ฒ€์‚ฌ๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋งŒ ์‹คํ–‰๋˜์ง€๋งŒ, ์ด๋ฏธ ์ฝ”๋“œ์— ์กด์žฌํ•˜๋Š” ๋ฒ„๊ทธ๋ฅผ ์ฐพ์•„๋‚ด๋Š” ๋ฐ ๋„์›€์„ ์ค๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฒ„๊ทธ๋Š” ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์žฌํ˜„ํ•˜๊ธฐ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Strict Mode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๊ณ ํ•˜๊ธฐ ์ „์— ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

Strict Mode์—์„œ๋Š” ๊ฐœ๋ฐœ ์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒ€์‚ฌ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ชจ๋“  ๊ฒ€์‚ฌ๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์ „์šฉ์ด๋ฉฐ ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


์•ฑ์˜ ์ผ๋ถ€๋ถ„์—์„œ Strict Mode ํ™œ์„ฑํ™”

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์–ด๋–ค ๋ถ€๋ถ„์—์„œ๋ผ๋„ Strict Mode๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { StrictMode } from 'react';

function App() {
return (
<>
<Header />
<StrictMode>
<main>
<Sidebar />
<Content />
</main>
</StrictMode>
<Footer />
</>
);
}

์ด ์˜ˆ์‹œ์—์„œ Header์™€ Footer ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” Strict Mode ๊ฒ€์‚ฌ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Sidebar์™€ Content, ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ž์† ์ปดํฌ๋„ŒํŠธ๋Š” ๊นŠ์ด์— ์ƒ๊ด€์—†์ด ๊ฒ€์‚ฌ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

์•ฑ์˜ ์ผ๋ถ€์—์„œ StrictMode๊ฐ€ ํ™œ์„ฑํ™”๋˜๋ฉด React๋Š” ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋งŒ ๊ฐ€๋Šฅํ•œ ๋™์ž‘๋งŒ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•ฑ์˜ ๋ฃจํŠธ์—์„œ <StrictMode>๊ฐ€ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์œผ๋ฉด ์ดˆ๊ธฐ ๋งˆ์šดํŠธ ์‹œ Effect๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ถ€๋ชจ Effect ์—†์ด ์ž์‹ Effect๊ฐ€ ๋‘ ๋ฒˆ ์‹คํ–‰๋˜๋Š” ์ƒํ™ฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•จ์ด๋ฉฐ, ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์€ ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


๊ฐœ๋ฐœ ์ค‘ ์ด์ค‘ ๋ Œ๋”๋ง์œผ๋กœ ๋ฐœ๊ฒฌํ•œ ๋ฒ„๊ทธ ์ˆ˜์ •

React๋Š” ์ž‘์„ฑํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ผ๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ React ์ปดํฌ๋„ŒํŠธ๋Š” ํ•ญ์ƒ ๋™์ผํ•œ ์ž…๋ ฅ(Props, State, Context)์— ๋Œ€ํ•ด ๋™์ผํ•œ JSX๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ทœ์น™์„ ์œ„๋ฐ˜ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ๋™์ž‘ํ•˜๋ฉฐ ๋ฒ„๊ทธ๋ฅผ ์ผ์œผํ‚ต๋‹ˆ๋‹ค. Strict Mode๋Š” ์‹ค์ˆ˜๋กœ ์ž‘์„ฑ๋œ ์ˆœ์ˆ˜ํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ ์ฐพ์•„๋‚ด๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ํ•จ์ˆ˜(์ˆœ์ˆ˜ ํ•จ์ˆ˜์—ฌ์•ผ ํ•˜๋Š” ๊ฒƒ๋งŒ)๋ฅผ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ํ•œ ๊ฒฝ์šฐ ๋‘ ๋ฒˆ ์‹คํ–‰ํ•˜์—ฌ๋„ ๋™์ž‘์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ํ•ญ์ƒ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ํ•˜์ง€ ์•Š๋‹ค๋ฉด (์˜ˆ: ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜) ๋‘ ๋ฒˆ ์‹คํ–‰ํ•˜๋ฉด ๋ณดํ†ต ์•Œ์•„์ฑŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์ด๊ฒƒ์ด ๋ฐ”๋กœ ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค!) ์ด๋Š” ๋ฒ„๊ทธ๋ฅผ ์กฐ๊ธฐ์— ๋ฐœ๊ฒฌํ•˜๊ณ  ์ˆ˜์ •ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ Strict Mode์˜ ์ด์ค‘ ๋ Œ๋”๋ง์ด ์–ด๋–ป๊ฒŒ ๋ฒ„๊ทธ๋ฅผ ์กฐ๊ธฐ์— ๋ฐœ๊ฒฌํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

StoryTray ์ปดํฌ๋„ŒํŠธ๋Š” stories ๋ฐฐ์—ด์„ ๋ฐ›์•„ ๋งˆ์ง€๋ง‰์— โ€œ์ด์•ผ๊ธฐ ๋งŒ๋“ค๊ธฐโ€ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

export default function StoryTray({ stories }) {
  const items = stories;
  items.push({ id: 'create', label: '์ด์•ผ๊ธฐ ๋งŒ๋“ค๊ธฐ' });
  return (
    <ul>
      {items.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

์œ„ ์ฝ”๋“œ์—๋Š” ์‹ค์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ดˆ๊ธฐ ์ถœ๋ ฅ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋‚˜ํƒ€๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ๋†“์น˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

This mistake will become more noticeable if the StoryTray component re-renders multiple times. For example, letโ€™s make the StoryTray re-render with a different background color whenever you hover over it:

import { useState } from 'react';

export default function StoryTray({ stories }) {
  const [isHover, setIsHover] = useState(false);
  const items = stories;
  items.push({ id: 'create', label: '์ด์•ผ๊ธฐ ๋งŒ๋“ค๊ธฐ' });
  return (
    <ul
      onPointerEnter={() => setIsHover(true)}
      onPointerLeave={() => setIsHover(false)}
      style={{
        backgroundColor: isHover ? '#ddd' : '#fff'
      }}
    >
      {items.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

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

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฐฐ์—ด์˜ ์‚ฌ๋ณธ์„ ๋งŒ๋“  ๋‹ค์Œ ์›๋ณธ์ด ์•„๋‹Œ ์‚ฌ๋ณธ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export default function StoryTray({ stories }) {
const items = stories.slice(); // ๋ฐฐ์—ด ๋ณต์ œ
// โœ… Good: ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์— ์ถ”๊ฐ€
items.push({ id: 'create', label: '์ด์•ผ๊ธฐ ๋งŒ๋“ค๊ธฐ' });

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

์›๋ž˜ ์˜ˆ์‹œ์—์„œ๋Š” ๋ฒ„๊ทธ๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด์ œ ์›๋ž˜ (๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š”) ์ฝ”๋“œ๋ฅผ <StrictMode>๋กœ ๋ž˜ํ•‘ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

export default function StoryTray({ stories }) {
  const items = stories;
  items.push({ id: 'create', label: '์ด์•ผ๊ธฐ ๋งŒ๋“ค๊ธฐ' });
  return (
    <ul>
      {items.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

Strict Mode์—์„œ๋Š” ํ•ญ์ƒ ๋ Œ๋”๋ง ํ•จ์ˆ˜๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ ์‹ค์ˆ˜๋ฅผ ๋ฐ”๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (โ€œ์ด์•ผ๊ธฐ ๋งŒ๋“ค๊ธฐโ€๊ฐ€ ๋‘ ๋ฒˆ ๋‚˜ํƒ€๋‚จ.) ๋”ฐ๋ผ์„œ ํ”„๋กœ์„ธ์Šค ์ดˆ๊ธฐ์— ์ด๋Ÿฌํ•œ ์‹ค์ˆ˜๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ Strict Mode์—์„œ ๋ Œ๋”๋ง๋˜๋„๋ก ์ˆ˜์ •ํ•˜๋ฉด ์ด์ „์˜ ํ˜ธ๋ฒ„ ๊ธฐ๋Šฅ๊ณผ ๊ฐ™์ด ํ–ฅํ›„ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋งŽ์€ ํ”„๋กœ๋•์…˜ ๋ฒ„๊ทธ๋„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { useState } from 'react';

export default function StoryTray({ stories }) {
  const [isHover, setIsHover] = useState(false);
  const items = stories.slice(); // ๋ฐฐ์—ด ๋ณต์ œ
  items.push({ id: 'create', label: '์ด์•ผ๊ธฐ ๋งŒ๋“ค๊ธฐ' });
  return (
    <ul
      onPointerEnter={() => setIsHover(true)}
      onPointerLeave={() => setIsHover(false)}
      style={{
        backgroundColor: isHover ? '#ddd' : '#fff'
      }}
    >
      {items.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

Strict Mode๊ฐ€ ์—†์œผ๋ฉด ๋ฆฌ๋ Œ๋”๋ง์„ ๋” ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ฒ„๊ทธ๋ฅผ ๋†“์น˜๊ธฐ ์‰ฌ์› ์Šต๋‹ˆ๋‹ค. Strict Mode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™์ผํ•œ ๋ฒ„๊ทธ๊ฐ€ ์ฆ‰์‹œ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. Strict Mode๋Š” ๋ฒ„๊ทธ๋ฅผ ํŒ€์ด๋‚˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘ธ์‹œํ•˜๊ธฐ ์ „์— ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋ฅผ ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์„ธ์š”.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

React ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ๋‹ค๋ฉด, ๋‘ ๋ฒˆ์งธ ๋ Œ๋”๋ง ํ˜ธ์ถœ ์ค‘ console.log ํ˜ธ์ถœ์ด ์•ฝ๊ฐ„ ํ๋ฆฌ๊ฒŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. React ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋Š” ์ด๋ฅผ ์™„์ „ํžˆ ์–ต์ œํ•˜๋Š” ์„ค์ •(๊ธฐ๋ณธ๊ฐ’์€ ๊บผ์ง)๋„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ Effect๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ ๋ฐœ๊ฒฌ๋œ ๋ฒ„๊ทธ ์ˆ˜์ •

Strict Mode๋Š” Effect์˜ ๋ฒ„๊ทธ๋ฅผ ์ฐพ๋Š” ๋ฐ๋„ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  Effect์—๋Š” ๋ช‡ ๊ฐ€์ง€ ์…‹์—… ์ฝ”๋“œ๊ฐ€ ์žˆ๊ณ  ์–ด์ฉŒ๋ฉด ํด๋ฆฐ์—… ์ฝ”๋“œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ React๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ(ํ™”๋ฉด์— ์ถ”๊ฐ€)๋  ๋•Œ ์…‹์—…์„ ํ˜ธ์ถœํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ ํ•ด์ œ(ํ™”๋ฉด์—์„œ ์ œ๊ฑฐ)๋  ๋•Œ ํด๋ฆฐ์—…์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ React๋Š” ๋งˆ์ง€๋ง‰ ๋ Œ๋”๋ง ์ดํ›„๋กœ๋ถ€ํ„ฐ ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ํด๋ฆฐ์—…๊ณผ ์…‹์—…์„ ๋‹ค์‹œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

Strict Mode๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฉด React๋Š” ๋ชจ๋“  Effect์— ๋Œ€ํ•ด ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ํ•œ ๋ฒˆ ๋” ์…‹์—…+ํด๋ฆฐ์—… ์‚ฌ์ดํด์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์˜์™ธ๋กœ ๋А๊ปด์งˆ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ˆ˜๋™์œผ๋กœ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฏธ๋ฌ˜ํ•œ ๋ฒ„๊ทธ๋ฅผ ๋“œ๋Ÿฌ๋‚ด๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ Strict Mode์—์„œ Effect๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋ฒ„๊ทธ๋ฅผ ์กฐ๊ธฐ์— ๋ฐœ๊ฒฌํ•˜๋Š” ๋ฐ ์–ด๋–ป๊ฒŒ ๋„์›€์ด ๋˜๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฑ„ํŒ…์— ์—ฐ๊ฒฐํ•˜๋Š” ์ด ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค.

import { createRoot } from 'react-dom/client';
import './styles.css';

import App from './App';

const root = createRoot(document.getElementById("root"));
root.render(<App />);

์ด ์ฝ”๋“œ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์ง€๋งŒ ์ฆ‰์‹œ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

import { createRoot } from 'react-dom/client';
import './styles.css';

import App from './App';

const root = createRoot(document.getElementById("root"));
root.render(<App />);

์—ด๋ฆฐ ์—ฐ๊ฒฐ ์ˆ˜๊ฐ€ ํ•ญ์ƒ ๊ณ„์† ์ฆ๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ์•ฑ์—์„œ๋Š” ์„ฑ๋Šฅ ๋ฐ ๋„คํŠธ์›Œํฌ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” Effect์— ํด๋ฆฐ์—… ํ•จ์ˆ˜๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]);

์ด์ œ Effect๊ฐ€ ์ž์ฒด์ ์œผ๋กœ โ€œํด๋ฆฐ์—…โ€ํ•˜๊ณ  ์˜ค๋ž˜๋œ ์—ฐ๊ฒฐ์„ ํŒŒ๊ดดํ•˜๋ฏ€๋กœ ๋ˆ„์ˆ˜๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋” ๋งŽ์€ ๊ธฐ๋Šฅ(์„ ํƒ ์ƒ์ž)์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š์•˜์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์›๋ž˜ ์˜ˆ์‹œ์—์„œ๋Š” ๋ฒ„๊ทธ๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด์ œ ์›๋ž˜ (๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š”) ์ฝ”๋“œ๋ฅผ <StrictMode>๋กœ ๋ž˜ํ•‘ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';

import App from './App';

const root = createRoot(document.getElementById("root"));
root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

Strict Mode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ์„ ์ฆ‰์‹œ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(ํ™œ์„ฑํ™”๋œ ์—ฐ๊ฒฐ ์ˆ˜๊ฐ€ 2๊ฐœ๋กœ ์ฆ๊ฐ€ํ•จ). Strict Mode๋Š” ๋ชจ๋“  Effect์— ๋Œ€ํ•ด ์ถ”๊ฐ€ ์…‹์—…+ํด๋ฆฐ์—… ์‚ฌ์ดํด์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด Effect์—๋Š” ํด๋ฆฐ์—… ๋กœ์ง์ด ์—†์œผ๋ฏ€๋กœ ์ถ”๊ฐ€ ์—ฐ๊ฒฐ์„ ์ƒ์„ฑํ•˜์ง€๋งŒ ํŒŒ๊ดดํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํด๋ฆฐ์—… ํ•จ์ˆ˜๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ๋‹ค๋Š” ํžŒํŠธ์ž…๋‹ˆ๋‹ค.

Strict Mode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ์‹ค์ˆ˜๋ฅผ ํ”„๋กœ์„ธ์Šค ์ดˆ๊ธฐ์— ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Strict Mode์—์„œ ํด๋ฆฐ์—… ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ Effect๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ์ด์ „์˜ ์„ ํƒ ์ƒ์ž์™€ ๊ฐ™์ด ํ–ฅํ›„ ํ”„๋กœ๋•์…˜์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋งŽ์€ ๋ฒ„๊ทธ ๋˜ํ•œ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';

import App from './App';

const root = createRoot(document.getElementById("root"));
root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

์ฝ˜์†”์˜ ํ™œ์„ฑํ™”๋œ ์—ฐ๊ฒฐ ์ˆ˜๊ฐ€ ๋” ์ด์ƒ ์ฆ๊ฐ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Strict Mode๊ฐ€ ์—†์œผ๋ฉด Effect๋ฅผ ํด๋ฆฐ์—…ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋†“์น˜๊ธฐ ์‰ฌ์› ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ Effect์— ๋Œ€ํ•ด ์…‹์—… ๋Œ€์‹  ์…‹์—… โ†’ ํด๋ฆฐ์—… โ†’ ์…‹์—…์„ ์‹คํ–‰ํ•˜๋ฉด Strict Mode์—์„œ ๋ˆ„๋ฝ๋œ ํด๋ฆฐ์—… ๋กœ์ง์ด ๋” ๋ˆˆ์— ๋„๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Effect ํด๋ฆฐ์—…์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์„ธ์š”.


๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ref ์ฝœ๋ฐฑ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ ๋ฐœ๊ฒฌ๋œ ๋ฒ„๊ทธ ์ˆ˜์ •

Strict Mode๋Š” callbacks refs์˜ ๋ฒ„๊ทธ๋ฅผ ์ฐพ๋Š” ๋ฐ๋„ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์ฝœ๋ฐฑ ref์—๋Š” ๋ช‡ ๊ฐ€์ง€ ์…‹์—… ์ฝ”๋“œ๊ฐ€ ์žˆ๊ณ  ์–ด์ฉŒ๋ฉด ํด๋ฆฐ์—… ์ฝ”๋“œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ React๋Š” ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ƒ์„ฑ(DOM์— ์ถ”๊ฐ€)๋  ๋•Œ ์…‹์—… ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ œ๊ฑฐ(DOM์—์„œ ์‚ญ์ œ)๋  ๋•Œ ์…‹์—… ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Strict Mode๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฉด React๋Š” ๋ชจ๋“  ์ฝœ๋ฐฑ ref์— ๋Œ€ํ•ด ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ํ•œ ๋ฒˆ ๋” ์…‹์—…+ํด๋ฆฐ์—… ์‚ฌ์ดํด์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด์™ธ๋กœ ๋А๊ปด์งˆ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ˆ˜๋™์œผ๋กœ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฏธ๋ฌ˜ํ•œ ๋ฒ„๊ทธ๋ฅผ ๋“œ๋Ÿฌ๋‚ด๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค. ์ด ์˜ˆ์‹œ๋Š” ๋™๋ฌผ์„ ์„ ํƒํ•œ ํ›„ ๋ชฉ๋ก ์ค‘ ํ•˜๋‚˜๋กœ ์Šคํฌ๋กค ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. โ€œcatsโ€์—์„œ โ€œdogsโ€๋กœ ์ „ํ™˜ํ•  ๋•Œ ์ฝ˜์†” ๋กœ๊ทธ๋ฅผ ๋ณด๋ฉด ๋ชฉ๋ก์— ์žˆ๋Š” ๋™๋ฌผ์˜ ์ˆ˜๊ฐ€ ๊ณ„์† ์ฆ๊ฐ€ํ•˜๊ณ , โ€œScroll toโ€ ๋ฒ„ํŠผ์ด ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ๋˜๋Š” ์ ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { useRef, useState } from "react";

export default function CatFriends() {
  const itemsRef = useRef([]);
  const [catList, setCatList] = useState(setupCatList);
  const [cat, setCat] = useState('neo');

  function scrollToCat(index) {
    const list = itemsRef.current;
    const {node} = list[index];
    node.scrollIntoView({
      behavior: "smooth",
      block: "nearest",
      inline: "center",
    });
  }

  const cats = catList.filter(c => c.type === cat)

  return (
    <>
      <nav>
        <button onClick={() => setCat('neo')}>Neo</button>
        <button onClick={() => setCat('millie')}>Millie</button>
      </nav>
      <hr />
      <nav>
        <span>Scroll to:</span>{cats.map((cat, index) => (
          <button key={cat.src} onClick={() => scrollToCat(index)}>
            {index}
          </button>
        ))}
      </nav>
      <div>
        <ul>
          {cats.map((cat) => (
            <li
              key={cat.src}
              ref={(node) => {
                const list = itemsRef.current;
                const item = {cat: cat, node};
                list.push(item);
                console.log(`โœ… Adding cat to the map. Total cats: ${list.length}`);
                if (list.length > 10) {
                  console.log('โŒ Too many cats in the list!');
                }
                return () => {
                  // ๐Ÿšฉ No cleanup, this is a bug!
                }
              }}
            >
              <img src={cat.src} />
            </li>
          ))}
        </ul>
      </div>
    </>
  );
}

function setupCatList() {
  const catList = [];
  for (let i = 0; i < 10; i++) {
    catList.push({type: 'neo', src: "https://placecats.com/neo/320/240?" + i});
  }
  for (let i = 0; i < 10; i++) {
    catList.push({type: 'millie', src: "https://placecats.com/millie/320/240?" + i});
  }

  return catList;
}

์ด๊ฒƒ์€ ํ”„๋กœ๋•์…˜ ๋ฒ„๊ทธ์ž…๋‹ˆ๋‹ค! ref ์ฝœ๋ฐฑ์ด ํด๋ฆฐ์—… ๊ณผ์ •์—์„œ ๋™๋ฌผ ๋ชฉ๋ก์„ ์ œ๊ฑฐํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋™๋ฌผ ๋ชฉ๋ก์ด ๊ณ„์† ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์ผ์œผ์ผœ ์‹ค์ œ ์•ฑ์—์„œ ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•ฑ์˜ ๋™์ž‘์„ ๋ง๊ฐ€๋œจ๋ฆฝ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ref ์ฝœ๋ฐฑ์ด ์Šค์Šค๋กœ ํด๋ฆฐ์—…์„ ํ•˜์ง€ ์•Š๋Š” ์ ์ž…๋‹ˆ๋‹ค.

<li
ref={node => {
const list = itemsRef.current;
const item = {animal, node};
list.push(item);
return () => {
// ๐Ÿšฉ No cleanup, this is a bug!
}
}}
</li>

์ด์ œ ์›๋ณธ (๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š”) ์ฝ”๋“œ๋ฅผ <StrictMode>๋กœ ๊ฐ์‹ธ๋ด…์‹œ๋‹ค.

import { useRef, useState } from "react";

export default function CatFriends() {
  const itemsRef = useRef([]);
  const [catList, setCatList] = useState(setupCatList);
  const [cat, setCat] = useState('neo');

  function scrollToCat(index) {
    const list = itemsRef.current;
    const {node} = list[index];
    node.scrollIntoView({
      behavior: "smooth",
      block: "nearest",
      inline: "center",
    });
  }

  const cats = catList.filter(c => c.type === cat)

  return (
    <>
      <nav>
        <button onClick={() => setCat('neo')}>Neo</button>
        <button onClick={() => setCat('millie')}>Millie</button>
      </nav>
      <hr />
      <nav>
        <span>Scroll to:</span>{cats.map((cat, index) => (
          <button key={cat.src} onClick={() => scrollToCat(index)}>
            {index}
          </button>
        ))}
      </nav>
      <div>
        <ul>
          {cats.map((cat) => (
            <li
              key={cat.src}
              ref={(node) => {
                const list = itemsRef.current;
                const item = {cat: cat, node};
                list.push(item);
                console.log(`โœ… Adding cat to the map. Total cats: ${list.length}`);
                if (list.length > 10) {
                  console.log('โŒ Too many cats in the list!');
                }
                return () => {
                  // ๐Ÿšฉ No cleanup, this is a bug!
                }
              }}
            >
              <img src={cat.src} />
            </li>
          ))}
        </ul>
      </div>
    </>
  );
}

function setupCatList() {
  const catList = [];
  for (let i = 0; i < 10; i++) {
    catList.push({type: 'neo', src: "https://placecats.com/neo/320/240?" + i});
  }
  for (let i = 0; i < 10; i++) {
    catList.push({type: 'millie', src: "https://placecats.com/millie/320/240?" + i});
  }

  return catList;
}

Strict Mode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ œ๋ฅผ ์ฆ‰์‹œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Strict Mode๋Š” ๋ชจ๋“  ์ฝœ๋ฐฑ ref์— ๋Œ€ํ•ด ์ถ”๊ฐ€์ ์ธ ์…‹์—…+ํด๋ฆฐ์—… ์‚ฌ์ดํด์„ ์‹คํ–‰ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ฝœ๋ฐฑ ref์—๋Š” ํด๋ฆฐ์—… ๋กœ์ง์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ref๋ฅผ ์ถ”๊ฐ€๋งŒ ํ•˜๊ณ  ์ œ๊ฑฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํด๋ฆฐ์—… ํ•จ์ˆ˜๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ๋‹ค๋Š” ํžŒํŠธ์ž…๋‹ˆ๋‹ค.

Strict Mode๋ฅผ ํ†ตํ•ด ์ฝœ๋ฐฑ ref์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์‹ค์ˆ˜๋ฅผ ์กฐ๊ธฐ์— ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Strict Mode์—์„œ ํด๋ฆฐ์—… ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฝœ๋ฐฑ์„ ์ˆ˜์ •ํ•˜๋ฉด, ์ด์ „์— ๋ฐœ์ƒํ–ˆ๋˜ โ€œScroll toโ€ ๋ฒ„๊ทธ์™€ ๊ฐ™์€ ๋งŽ์€ ์ž ์žฌ์ ์ธ ํ”„๋กœ๋•์…˜ ๋ฒ„๊ทธ๋„ ํ•จ๊ป˜ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { useRef, useState } from "react";

export default function CatFriends() {
  const itemsRef = useRef([]);
  const [catList, setCatList] = useState(setupCatList);
  const [cat, setCat] = useState('neo');

  function scrollToCat(index) {
    const list = itemsRef.current;
    const {node} = list[index];
    node.scrollIntoView({
      behavior: "smooth",
      block: "nearest",
      inline: "center",
    });
  }

  const cats = catList.filter(c => c.type === cat)

  return (
    <>
      <nav>
        <button onClick={() => setCat('neo')}>Neo</button>
        <button onClick={() => setCat('millie')}>Millie</button>
      </nav>
      <hr />
      <nav>
        <span>Scroll to:</span>{cats.map((cat, index) => (
          <button key={cat.src} onClick={() => scrollToCat(index)}>
            {index}
          </button>
        ))}
      </nav>
      <div>
        <ul>
          {cats.map((cat) => (
            <li
              key={cat.src}
              ref={(node) => {
                const list = itemsRef.current;
                const item = {cat: cat, node};
                list.push(item);
                console.log(`โœ… Adding cat to the map. Total cats: ${list.length}`);
                if (list.length > 10) {
                  console.log('โŒ Too many cats in the list!');
                }
                return () => {
                  list.splice(list.indexOf(item), 1);
                  console.log(`โŒ Removing cat from the map. Total cats: ${itemsRef.current.length}`);
                }
              }}
            >
              <img src={cat.src} />
            </li>
          ))}
        </ul>
      </div>
    </>
  );
}

function setupCatList() {
  const catList = [];
  for (let i = 0; i < 10; i++) {
    catList.push({type: 'neo', src: "https://placecats.com/neo/320/240?" + i});
  }
  for (let i = 0; i < 10; i++) {
    catList.push({type: 'millie', src: "https://placecats.com/millie/320/240?" + i});
  }

  return catList;
}

์ด์ œ StrictMode์—์„œ ์ดˆ๊ธฐ ๋งˆ์šดํŠธ ์‹œ, ref ์ฝœ๋ฐฑ์ด ๋ชจ๋‘ ์…‹์—…๋˜๊ณ , ํด๋ฆฐ์—… ํ›„, ๋‹ค์‹œ ์…‹์—… ๋ฉ๋‹ˆ๋‹ค.

...
โœ… ๋™๋ฌผ์„ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•˜๋Š” ์ค‘. ์ด ๋™๋ฌผ ์ˆ˜: 10
...
โŒ ๋ชฉ๋ก์—์„œ ๋™๋ฌผ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๋™๋ฌผ ์ˆ˜: 0
...
โœ… ๋™๋ฌผ์„ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•˜๋Š” ์ค‘. ์ด ๋™๋ฌผ ์ˆ˜: 10

์ด๊ฒƒ์ด ์˜ˆ์ƒ๋œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. Strict Mode๋Š” ref ์ฝœ๋ฐฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํด๋ฆฐ์—… ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํฌ๊ธฐ๊ฐ€ ์˜ˆ์ƒ๋œ ์–‘์„ ์ดˆ๊ณผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ˆ˜์ • ํ›„์—๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๋ชจ๋“  ๊ธฐ๋Šฅ์ด ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

Strict Mode ์—†์ด๋Š” ๊ณ ์žฅ ๋‚œ ๊ธฐ๋Šฅ์„ ์•Œ์•„์ฐจ๋ฆด ๋•Œ๊นŒ์ง€ ์—ฌ๊ธฐ์ €๊ธฐ ํด๋ฆญํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฒ„๊ทธ๋ฅผ ๋†“์น˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. Strict Mode๋Š” ๋ฒ„๊ทธ๋ฅผ ์ฆ‰์‹œ ๋“œ๋Ÿฌ๋‚˜๋„๋ก ํ•˜์—ฌ ํ”„๋กœ๋•์…˜์— ๋ฐฐํฌํ•˜๊ธฐ ์ „์— ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


Fixing deprecation warnings enabled by Strict Mode

React๋Š” <StrictMode> ํŠธ๋ฆฌ ๋‚ด๋ถ€์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋‹ค์Œ API ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๊ฒฝ๊ณ ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ API๋Š” ์ฃผ๋กœ ์ด์ „ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ ์ตœ์‹  ์•ฑ์—์„œ๋Š” ๊ฑฐ์˜ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.