ChatGPT ๋กœ React ์ƒํƒœ ๊ด€๋ฆฌ ๊ณต๋ถ€ํ•ด๋ณด๊ธฐ

๋™๋ฃŒ๋ถ„์ด ๊ณต์œ ์ฃผ์‹  XL8 ๋ฐฐํœ˜๋™๋‹˜์˜ ์„ธ๋ฏธ๋‚˜ ๊ณต์œ ์šฉ PPT ๋ฅผ ๋ณด๊ณ , ์ƒํƒœ ๊ด€๋ฆฌ ๊ด€๋ จํ•ด์„œ ๋‚ด๊ฐ€ ์–ด๋А ์ •๋„ ์•Œ๊ณ  ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๋Š” ๊ฑด ์—†๋Š”์ง€ ๋ณด๊ณ  ์‹ถ์€๋งˆ์Œ์— ChatGPT ๋ฅผ ์ด์šฉํ•ด์„œ ๊ณต๋ถ€๋ฅผ ํ•ด๋ดค๋‹ค. ์šฐ์„  ์•„๋ž˜๋Š” 4๊ฐœ์˜ ์ด๋ฏธ์ง€๋ฅผ ๋ถ™์—ฌ๋„ฃ๊ณ  ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋‹ฌ๋ผ๊ณ  ํ•ด์„œ ์ •๋ฆฌํ•œ ๋‚ด์šฉ.

 

์ •๋ฆฌํ•œ ๋‚ด์šฉ

useState ์ˆ˜๋ จ์ƒ

  • useState ์‚ฌ์šฉํ•ด ์ƒํƒœ ์—…๋ฐ์ดํŠธ
  • props ์ „๋‹ฌ ์œ„์ฃผ๋กœ ๊ตฌ์„ฑ
  • ๊ฐ„๋‹จํ•œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

 

์˜์‚ฌ๊ฒฐ์ • ํฌ์ธํŠธ

  • "์ด๊ฑด ์ƒํƒœ๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•ด?"
  • "๊ทธ๋ƒฅ ๋ณ€์ˆ˜์—ฌ๋„ ๋˜๋Š” ๊ฑฐ ์•„๋‹Œ๊ฐ€?"

์ž์ฃผ ๊ฒช๋Š” ๋ฌธ์ œ

  • ๋ถˆํ•„์š”ํ•œ ์ƒํƒœ ์„ ์–ธ
  • ๋™๊ธฐ/๋น„๋™๊ธฐ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ๊ฐœ๋… ๋ถ€์กฑ
  • props vs state ํ˜ผ๋™

 

Props & ์ƒํƒœ ํƒ์ƒ‰๊ฐ€

  • ์ƒํƒœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ (lifting state)
  • ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ์ƒํƒœ ๊ณต์œ  ๊ณ ๋ฏผ
  • ๋ณต์žกํ•œ ์ด๋ฒคํŠธ ์กฐํ•ฉ ์ฒ˜๋ฆฌ
function Parent() {
  const [name, setName] = useState("");

  return (
    <div>
      <Input name={name} onChange={setName} />
      <Preview name={name} />
    </div>
  );
}

function Input({ name, onChange }: { name: string; onChange: (v: string) => void }) {
  return <input value={name} onChange={(e) => onChange(e.target.value)} />;
}

function Preview({ name }: { name: string }) {
  return <p>Preview: {name}</p>;
}

 

์˜์‚ฌ๊ฒฐ์ • ํฌ์ธํŠธ

  • "์ด ์ƒํƒœ๋Š” ์–ด๋””์— ์žˆ์–ด์•ผ ํ• ๊นŒ?"
  • "Props๋กœ ์ค„๊นŒ, Context๋กœ ๊ณต์œ ํ• ๊นŒ?"

์ž์ฃผ ๊ฒช๋Š” ๋ฌธ์ œ

  • ๊ณผ๋„ํ•œ props drilling
  • ๋ฆฌ๋ Œ๋”๋ง ๋ณ‘๋ชฉ ๋ฐœ์ƒ
  • ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ๊ฒฝ๊ณ„ ๋ถˆ๋ถ„๋ช…

 

์ƒํƒœ ํ๋ฆ„ ์„ค๊ณ„์ž

  • Context, useReducer ์‚ฌ์šฉ ์‹œ์ž‘
  • ์ƒํƒœ ํ๋ฆ„ ๊ตฌ์กฐํ™”
  • memo, useMemo, useCallback ์‹œ์ž‘
const CounterContext = React.createContext(null);

function CounterProvider({ children }) {
  const [count, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case 'INC':
        return state + 1;
      default:
        return state;
    }
  }, 0);

  return (
    <CounterContext.Provider value={{ count, dispatch }}>
      {children}
    </CounterContext.Provider>
  );
}

function Child() {
  const { count, dispatch } = useContext(CounterContext);
  return (
    <button onClick={() => dispatch({ type: 'INC' })}>
      {count}
    </button>
  );
}

 

์˜์‚ฌ๊ฒฐ์ • ํฌ์ธํŠธ

  • "Prop drilling์ด ๋„ˆ๋ฌด ์‹ฌํ•ด. Context๋กœ ํ’€๊นŒ?"
  • "์ด๊ฑด ๋ณต์žกํ•œ ๋กœ์ง์ด๋‹ˆ useReducer ์จ์•ผ ํ• ๊นŒ?"

์ž์ฃผ ๊ฒช๋Š” ๋ฌธ์ œ

  • ์„ฑ๊ธ‰ํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™” (memo ๋‚จ์šฉ)
  • Context ๋‚จ์šฉ (์ „์—ญ์ฒ˜๋Ÿผ ์‚ฌ์šฉ)
  • ๋กœ์ปฌ๋กœ ์ถฉ๋ถ„ํ•œ ์ƒํƒœ๋„ ์ „์—ญํ™”

 

๊ธฐ๋ณธ๊ธฐ ๋งˆ์Šคํ„ฐ

  • ๋ชจ๋“  ์ƒํƒœ ๊ด€๋ฆฌ ๋„๊ตฌ ์ˆ™๋ จ (useState, useReducer, Context, Recoil, Zustand ๋“ฑ)
  • ๋ชฉ์ ์— ๋งž๋Š” ๋„๊ตฌ ์„ ํƒ
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”, ๋ฆฌํŒฉํ† ๋ง ์„ค๊ณ„ ๋Šฅ๋ ฅ
// ์ƒํƒœ๋ฅผ slice๋ณ„๋กœ ์ชผ๊ฐœ์„œ useContext, useMemo, useReducer ์กฐํ•ฉ
// ๋˜๋Š” ํ•„์š”์— ๋”ฐ๋ผ Zustand ๋“ฑ์˜ ์™ธ๋ถ€ ์ƒํƒœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™œ์šฉ

// ex: Zustand
import { create } from 'zustand';

const useStore = create((set) => ({
  user: null,
  setUser: (user) => set({ user }),
}));

function Profile() {
  const user = useStore((state) => state.user);
  const setUser = useStore((state) => state.setUser);

  return (
    <div>
      <p>{user?.name}</p>
      <button onClick={() => setUser({ name: '๋ ›์‹œ' })}>Set User</button>
    </div>
  );
}

 

์˜์‚ฌ๊ฒฐ์ • ํฌ์ธํŠธ

  • "์–ด๋–ค ์ ‘๊ทผ ๋ฐฉ์‹์ด ์ด ์‹œ๋‚˜๋ฆฌ์˜ค์— ๊ฐ€์žฅ ์ ์ ˆํ•œ๊ฐ€?"
  • "์ง€๊ธˆ memoization์€ ์‹ค์งˆ์ ์ธ ์ด๋“์ด ์žˆ๋Š”๊ฐ€?"
  • "์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์„ฑ๋Šฅ ์‚ฌ์ด์—์„œ ์ตœ์  ๊ตฌ์กฐ๋Š”?"

์ž์ฃผ ๊ฒช๋Š” ๋ฌธ์ œ

  • ์˜ค๋ฒ„์—”์ง€๋‹ˆ์–ด๋ง
  • ์ƒํƒœ ๊ตฌ์กฐ/๊ฒฐ์ • ๋ฌธ์„œํ™” ๋ถ€์กฑ

์ด์ œ ์ด ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ฌธ์ œ๋ฅผ ๋‚ด๋‹ฌ๋ผ๊ณ  ๋ถ€ํƒํ–ˆ๋‹ค.

๐Ÿงฉ ๋ฌธ์ œ: ์œ ์ € ๋Œ€์‹œ๋ณด๋“œ ์•ฑ

๋„ˆ๋Š” ๋Œ€์‹œ๋ณด๋“œ ํ™”๋ฉด์„ ๊ฐœ๋ฐœ ์ค‘์ด์•ผ. ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์•„:

<Dashboard>
โ”œโ”€โ”€ <UserProfile />         // ์œ ์ € ์ด๋ฆ„, ํ”„๋กœํ•„ ์ด๋ฏธ์ง€
โ”œโ”€โ”€ <UserStats />           // ์œ ์ € ํฌ์ธํŠธ, ํ™œ๋™ ํ†ต๊ณ„ ๋“ฑ
โ””โ”€โ”€ <UserPosts />           // ์œ ์ €๊ฐ€ ์ž‘์„ฑํ•œ ๊ฒŒ์‹œ๊ธ€ ๋ฆฌ์ŠคํŠธ
       โ””โ”€โ”€ <PostItem />     // ๊ฐ๊ฐ์˜ ๊ฒŒ์‹œ๊ธ€ (์ข‹์•„์š”, ๋Œ“๊ธ€ ๋“ฑ ํฌํ•จ)

 

๐Ÿ“ ์กฐ๊ฑด

  1. ํŽ˜์ด์ง€์— ์ง„์ž…ํ•˜๋ฉด /api/me ์—์„œ ์œ ์ € ์ •๋ณด(id, name, profileImage)๋ฅผ fetchํ•ด์„œ ์‚ฌ์šฉํ•จ.
  2. /api/posts?userId=xxx ์—์„œ ํ•ด๋‹น ์œ ์ €์˜ ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก์„ fetch.
  3. UserProfile, UserStats, UserPosts๋Š” ๊ฐ๊ฐ ๋ณ„๋„ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ๋œ ์ปดํฌ๋„ŒํŠธ.
  4. PostItem์—์„œ ์œ ์ € ์ด๋ฆ„์„ ํ‘œ์‹œํ•  ์ผ์ด ์žˆ๋‹ค. (์ž‘์„ฑ์ž: ๋ ›์‹œ ์ด๋Ÿฐ ๋А๋‚Œ)

โ“์งˆ๋ฌธ: ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒŒ ๊ฐ€์žฅ ํšจ์œจ์ ์ผ๊นŒ?

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

๐Ÿ“ฅ ๋„ค๊ฐ€ ๋‹ตํ•  ๋•Œ ์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์€ ํฌ์ธํŠธ

  • "User ์ •๋ณด๋Š” ์ž์ฃผ ๋ฐ”๋€Œ์ง€ ์•Š์•„" → ์–ด๋–ค ์ƒํƒœ ๊ด€๋ฆฌ ์ „๋žต์ด ์ ํ•ฉํ• ๊นŒ?
  • "PostItem๊นŒ์ง€ ์œ ์ € ์ด๋ฆ„์ด ํ•„์š”ํ•ด" → props๋กœ ๋„˜๊ธธ์ง€, ์ „์—ญ ์ƒํƒœ๋กœ ๋‘˜์ง€?
  • "์ปดํฌ๋„ŒํŠธ๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ํŒŒ์ผ์— ํฉ์–ด์ ธ ์žˆ์–ด" → ์ •๋ณด ๊ณต์œ ๋Š” ์–ด๋–ป๊ฒŒ?

์ด ๋ฌธ์ œ๋ฅผ ๋ณด๊ณ  ์ ์–ด๋ณธ ๋‚˜์˜ ๋‹ต๋ณ€

1. ์œ ์ € ์ •๋ณด ์ƒํƒœ์™€ ๊ฒŒ์‹œ๊ธ€ ์ƒํƒœ๋ฅผ ์–ด๋””์„œ ๊ด€๋ฆฌํ• ๋ž˜?

๊ฒŒ์‹œ๋ฌผ ๋ฆฌ์ŠคํŠธ์—์„œ api ํ˜ธ์ถœ ์‹œ userId ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์œ ์ € ์ •๋ณด๋Š” Dashboard ์ปดํฌ๋„ŒํŠธ์—์„œ UserContextProvider ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„. ์œ ์ € ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ฑด ์ธ์ฆ์ด ํ•„์š”ํ•ด์„œ ์ฟ ํ‚ค์— ๋‹ด๊ธด ์ธ์ฆ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š”๋ฐ, ServerSide Rendering ์„ ํ†ตํ•ด์„œ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์˜ ๋ธŒ๋ผ์šฐ์ € req.headers ๋ฅผ ์ฐธ์กฐํ•ด์„œ ๋ฏธ๋ฆฌ ์œ ์ € ์ •๋ณด๋ฅผ ๋ฐ›์•„๋‘˜ ์ˆ˜ ์žˆ์œผ๋ฉด ๋‹ค๋ฅธ api ๋“ค์„ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ui ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š”๋ฐ์— ๊ฑธ๋ฆฌ๋Š” ์š”์†Œ๊ฐ€ ์—†์„๊ฑฐ์•ผ. ์œ ์ € ์ •๋ณด๋Š” ์œ ์ €์˜ ์ธํ„ฐ๋ž™์…˜์— ์˜ํ•ด ์‰ฝ๊ฒŒ ๋ณ€ํ•˜๋Š” ์ •๋ณด๋„ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์˜ Context ๋กœ ๊ตฌ์„ฑํ•ด๋„ ํฌ๊ฒŒ ๋ฌธ์ œ ๋˜์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™์•„.

๊ฒŒ์‹œ๊ธ€ ์ƒํƒœ๋Š” UserPosts ์—์„œ ๋‹ค๋ฃฐ ๊ฒƒ ๊ฐ™์•„. ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์™€๋Š” ์ƒ๊ด€์ด ์—†์–ด์„œ. ๊ฐ๊ฐ์˜ ๊ฒŒ์‹œ๊ธ€์„ ๋‚˜ํƒ€๋‚ด๋Š” PostItem ์ด props ๋กœ ๊ฒŒ์‹œ๊ธ€ ๊ด€๋ จ ์ •๋ณด๋ฅผ ๋‚ด๋ ค๋ฐ›๋Š” ๊ตฌ์กฐ๊ฐ€ ๋  ๊ฑฐ ๊ฐ™์•„. depth ๊ฐ€ ํ•œ๋ฒˆ ํƒ€๊ณ ๋“ค์–ด๊ฐ€๋Š”๊ฑฐ๋ผ props driling๋„ ์‹ฌํ•˜์ง€ ์•Š์•„. ๋‹ค๋งŒ, PostItem ์—์„œ ์ข‹์•„์š”, ๋Œ“๊ธ€ ์„ ๋ˆŒ๋Ÿฌ์„œ ๊ฒŒ์‹œ๊ธ€์˜ ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธ ํ•ด์•ผ ํ•  ๋•Œ, api ๋ฅผ ์š”์ฒญํ•˜๊ณ  ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋‹ˆ๊นŒ ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ๋ฅผ ํ•˜๋Š”๊ฒŒ ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์„œ ๊ฒŒ์‹œ๊ธ€ ๊ฐ๊ฐ์—์„œ ๋‚ด๋ ค๋ฐ›์€ ์ข‹์•„์š”๋‚˜ ๋Œ“๊ธ€ ์ •๋ณด๋ฅผ state ์˜ initial ๊ฐ’์œผ๋กœ ๋ฐ›์•„์„œ ํ‘œ์‹œํ•˜๊ณ , ์ธํ„ฐ๋ž™์…˜ ํ›„์—๋Š” ์ฆ‰์‹œ state ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  api ๋ฅผ ์š”์ฒญํ•˜๋Š” ์‹์œผ๋กœ ๊ตฌํ˜„ํ• ๊ฑฐ์•ผ. api ์˜ ์‘๋‹ต์ด ์˜ค๋ฉด ์ด state ๋ฅผ ์œ ์ง€ํ•  ์ง€ / ์˜ค๋ฅ˜๋ฅผ ํ‘œ์‹œํ•  ์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์•„. ๋งŒ์•ฝ react-query ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉด, ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ๋กœ ํ•˜์ง€ ์•Š๊ณ  ๊ฒŒ์‹œ๊ธ€ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” api ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋Š” key ๋ฅผ ๊ฐ€์ง€๊ณ  ์ข‹์•„์š”๋‚˜ ๋Œ“๊ธ€ ์ƒํƒœ๋ฅผ ํŠน์ • id ์˜ ๊ฒŒ์‹œ๊ธ€์—์„œ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๋ฐฉ์‹์„ ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„. ๋ญ๊ฐ€ ์ข‹์„์ง€ ๊ณ ๋ฏผ์ด๋„ค.

 

2. ์–ด๋–ค ์ƒํƒœ ๊ด€๋ฆฌ ๋„๊ตฌ๋ฅผ ์“ธ๋ž˜?

์œ ์ € ์ •๋ณด๋Š” Context. ๋‚˜๋จธ์ง€๋Š” state ๋กœ ๊ฐ€๋Šฅํ•  ๊ฒƒ ๊ฐ™์•„. react-query ๋ฅผ ์“ฐ๋ฉด ์ข‹์€๋ฐ ๊ผญ ์“ธ ํ•„์š”๋Š” ์—†์–ด.

 

3.  "์ปดํฌ๋„ŒํŠธ๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ํŒŒ์ผ์— ํฉ์–ด์ ธ ์žˆ์–ด" → ์ •๋ณด ๊ณต์œ ๋Š” ์–ด๋–ป๊ฒŒ?

Context ๋กœ ์กฐํ•ฉํ•ด์„œ ๋ฌถ๊ฑฐ๋‚˜ global ์ƒํƒœ๋ฅผ ๋‹ค๋ฃจ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด.

 

GPT ์”จ์˜ ํ”ผ๋“œ๋ฐฑ

1. ์ข‹์•˜๋˜ ์ 

 

1. Context ์œ„์น˜์™€ ์œ ์ € ์ •๋ณด์˜ ํŠน์„ฑ์— ๋Œ€ํ•œ ํŒ๋‹จ

  • "์œ ์ € ์ •๋ณด๋Š” ์ž์ฃผ ๋ฐ”๋€Œ์ง€ ์•Š๊ณ  ์ƒ์œ„ Context์— ๋‘ฌ๋„ ๋ฌธ์ œ๋˜์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™๋‹ค."
  • ์ •ํ™•ํ•ด. ์ด๋Ÿฐ ์‹์œผ๋กœ ๋ถˆ๋ณ€์— ๊ฐ€๊นŒ์šด ๋ฐ์ดํ„ฐ๋Š” ์ƒ์œ„์— ๋‘๊ณ  Context๋กœ ๋ฐฐํฌํ•˜๋Š” ๊ฒŒ ์ข‹๊ณ , ๋ Œ๋”๋ง ๋น„์šฉ์ด ํฐ ๋ฐ์ดํ„ฐ๋Š” ํ”ผํ•˜๋Š” ๊ฒŒ ํ•ต์‹ฌ์ด์•ผ.
  • SSR์—์„œ ๋ฏธ๋ฆฌ ์œ ์ € ์ •๋ณด๋ฅผ ๋ฐ›์•„๋‘๋Š” ์ „๋žต๊นŒ์ง€ ์–ธ๊ธ‰ํ•œ ๊ฑด ์ง„์งœ ๐Ÿ‘
  • → getServerSideProps or app/layout.tsx ์ˆ˜์ค€์—์„œ ํ”„๋ฆฌํŒจ์นญํ•˜๋Š” ๊ตฌ์กฐ, ์‹ค๋ฌด์—์„œ ๋งค์šฐ ์ž์ฃผ ์”€.

2. ๊ฒŒ์‹œ๊ธ€์€ ๋กœ์ปฌ ์ƒํƒœ๋กœ, props๋กœ ์ „๋‹ฌํ•˜๋Š” ์ „๋žต

  • "UserPosts ๋‚ด์—์„œ ๊ฒŒ์‹œ๊ธ€ ์ƒํƒœ ๊ด€๋ฆฌ, PostItem์—” props๋กœ ๋„˜๊ธฐ๊ธฐ"
  • ๋ณต์žก๋„ ์ตœ์†Œํ™”์— ์ง‘์ค‘ํ•œ ๊ตฌ์กฐ. depth 1์ด๋ผ props๋กœ ์ถฉ๋ถ„ํ•˜๋‹ค๋Š” ํŒ๋‹จ๋„ ํ•ฉ๋ฆฌ์ .
  • ๊ตณ์ด Context๋‚˜ ๊ธ€๋กœ๋ฒŒ ์ƒํƒœ ์•ˆ ์“ฐ๊ณ  ์ง€์—ญํ™” ํ•œ ๊ฒƒ๋„ ์ž˜ํ–ˆ์–ด.

3. ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ ์ „๋žต ๊ณ ๋ฏผ

  • "state ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ๋‚ด๋ ค๋ฐ›๊ณ , optimistic update ์ ์šฉ → API ์‘๋‹ต์— ๋”ฐ๋ผ rollback"
  • ์ด๊ฑด ํ™•์‹คํžˆ ์ƒํƒœ ๊ด€๋ฆฌ ๊ณ ์ˆ˜๋งŒ์ด ๋ฐ”๋กœ ๋– ์˜ฌ๋ฆฌ๋Š” ๋ฐฉ์‹์ด์•ผ.
  • ์‹ค์ „์—์„œ๋Š” onMutate, onError, onSettled ํŒจํ„ด (react-query) ์ด๋ž‘ ๋”ฑ ๋งค์นญ๋จ.

 

2. ๊ฐœ์„  ํฌ์ธํŠธ & ๋Œ€์•ˆ ์ œ์•ˆ

 

๐Ÿ” PostItem ์˜ ์ƒํƒœ๋ฅผ ์–ด๋””์„œ ๊ด€๋ฆฌํ• ์ง€

  • ํ˜„์žฌ ๊ตฌ์กฐ๋„ ์ข‹์ง€๋งŒ, ๋‹ค์Œ๋„ ๊ณ ๋ ค ๊ฐ€๋Šฅํ•ด:

๋Œ€์•ˆ 1: PostItem ๋‚ด๋ถ€์—์„œ๋งŒ ์ƒํƒœ ๋ณ€๊ฒฝ ๊ด€๋ฆฌ

tsx
๋ณต์‚ฌํŽธ์ง‘
function PostItem({ post }: { post: Post }) {
  const [likes, setLikes] = useState(post.likes);
  const handleLike = () => {
    setLikes((prev) => prev + 1); // optimistic
    api.likePost(post.id).catch(() => setLikes((prev) => prev - 1)); // rollback
  };
}

  • ์ด๊ฑด ์ง€๊ธˆ ๋งํ•œ ๋ฐฉ์‹์ด๊ณ  ์ข‹์•„.

๋Œ€์•ˆ 2: UserPosts์—์„œ ์ „์ฒด posts ์ƒํƒœ๋ฅผ ๊ฐ€์ง„ ๋’ค, PostItem์€ ์ฝœ๋ฐฑ์„ ๋ฐ›์•„ ์—…๋ฐ์ดํŠธ๋งŒ ์š”์ฒญ

tsx
๋ณต์‚ฌํŽธ์ง‘
function UserPosts() {
  const [posts, setPosts] = useState<Post[]>(...);

  const updatePost = (id, patch) => {
    setPosts((prev) =>
      prev.map((p) => (p.id === id ? { ...p, ...patch } : p))
    );
  };

  return posts.map((post) => (
    <PostItem key={post.id} post={post} onUpdate={updatePost} />
  ));
}

  • ์žฅ์ : ์ค‘์•™์—์„œ ๋ชจ๋“  ๊ฒŒ์‹œ๊ธ€ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌ
  • ๋‹จ์ : ์กฐ๊ธˆ ๋” ๋ณต์žกํ•ด์ง€๊ณ , ์„ฑ๋Šฅ ์ด์Šˆ ์žˆ์„ ์ˆ˜ ์žˆ์Œ

 

3. ๊ฒฐ๋ก 

  • ์ „์ฒด์ ์ธ ๊ตฌ์กฐ ํŒ๋‹จ: ๋งค์šฐ ํ›Œ๋ฅญํ•ด. ์‹ค์ „๊ณผ๋„ 90% ์ด์ƒ ์ผ์น˜.
  • ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ๋Š” Context, UI์— ๋ฏผ๊ฐํ•œ ์ƒํ˜ธ์ž‘์šฉ์€ ์ง€์—ญ ์ƒํƒœ,
  • ์ด๊ฑธ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ตฌ๋ถ„ํ•ด๋ƒˆ๋‹ค๋Š” ๊ฑด ์ƒํƒœ ๊ด€๋ฆฌ ๋งˆ์Šคํ„ฐ์— ๊ฑฐ์˜ ๋‹ค ์™”๋‹ค๋Š” ๋œป์ด์•ผ.
  • react-query ์–ธ๊ธ‰๋„ ์ข‹์•˜๊ณ , ๊ผญ ์•ˆ ์จ๋„ ๋œ๋‹ค๋Š” ๊ฒƒ๋„ ์ƒํ™ฉ ํŒ๋‹จ๋ ฅ ์žˆ์Œ.

ํ”ผ๋“œ๋ฐฑ๋„ ์ž˜ ์ฃผ๊ณ  ๋ฌธ์ œ๋„ ์ž˜ ๋‚ด์ค˜์„œ ์žฌ๋ฐŒ์—ˆ๋‹ค. ๋‹ค์Œ์— ๋˜ ์ด์–ด์„œ ํ•ด๋ด์•ผ์ง€.

๋ฐ˜์‘ํ˜•