August 3, 2025

๐ŸŽญ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ์ง€์˜ฅ: ๋ณต์žกํ•œ ์‚ผํ•ญ ์—ฐ์‚ฐ์ž์™€ && ๋‚จ๋ฐœ, ๊ฐ€๋…์„ฑ ๋ฐ ์œ ์ง€๋ณด์ˆ˜์„ฑ ์ €ํ•˜

React
์ปดํฌ๋„ŒํŠธ
์•„ํ‚คํ…์ฒ˜
UX
๋„ค์ด๋ฐ
JavaScript

Summary

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

Why Wrong?

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

How to Fix?

๋ณต์žกํ•œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๋กœ์ง์„ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๋Œ€์‹ , ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ: ์กฐ๊ฑด๋ณ„๋กœ ๋ Œ๋”๋ง๋˜๋Š” ๋ถ€๋ถ„์„ ๋ณ„๋„์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ฅธ UI ๋ Œ๋”๋ง๋งŒ์„ ๋‹ด๋‹นํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ์ฑ…์ž„ ๋ฒ”์œ„๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜๊ณ , ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ๋†’์—ฌ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  2. ํ—ฌํผ ํ•จ์ˆ˜ ์‚ฌ์šฉ: ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๋กœ์ง์„ ํ—ฌํผ ํ•จ์ˆ˜๋กœ ์ถ”์ถœํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ํ—ฌํผ ํ•จ์ˆ˜๋Š” ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ Œ๋”๋งํ•  JSX๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜, ์ปดํฌ๋„ŒํŠธ props๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ๋ณต์žก๋„๋ฅผ ์ค„์ด๊ณ , ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.
  3. ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ (HOC) ๋˜๋Š” Render Props: ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง ๋กœ์ง์„ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋‚˜ Render Props ํŒจํ„ด์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๋กœ์ง์„ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ ์บก์Аํ™”ํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Before Code (Bad)

function MyComponent({ isLoading, data, error, isAdmin }) {
  return (
    <div>
      {isLoading ? (
        <p>Loading...</p>
      ) : error ? (
        <p>Error: {error.message}</p>
      ) : data ? (
        isAdmin ? (
          <div>
            <h1>Welcome Admin</h1>
            <p>Data: {data.value}</p>
            <button>Edit</button>
          </div>
        ) : (
          <div>
            <h1>Welcome User</h1>
            <p>Data: {data.value}</p>
          </div>
        )
      ) : (
        <p>No data available.</p>
      )}
    </div>
  );
}

After Code (Good)

// ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ
function Loading() {
  return <p>Loading...</p>;
}

function ErrorMessage({ error }) {
  return <p>Error: {error.message}</p>;
}

function AdminView({ data }) {
  return (
    <div>
      <h1>Welcome Admin</h1>
      <p>Data: {data.value}</p>
      <button>Edit</button>
    </div>
  );
}

function UserView({ data }) {
  return (
    <div>
      <h1>Welcome User</h1>
      <p>Data: {data.value}</p>
    </div>
  );
}

function NoData() {
    return <p>No data available.</p>
}

function MyComponent({ isLoading, data, error, isAdmin }) {
  if (isLoading) {
    return <Loading />;
  }

  if (error) {
    return <ErrorMessage error={error} />;
  }

  if (!data) {
    return <NoData />
  }

  return isAdmin ? <AdminView data={data} /> : <UserView data={data} />;
}