[React] ๊ฐ์ฒด ์ƒํƒœ๋ฅผ ํ™œ์šฉํ•œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๊ตฌํ˜„ (#09-1)

  • React
[React] ๊ฐ์ฒด ์ƒํƒœ๋ฅผ ํ™œ์šฉํ•œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๊ตฌํ˜„ (#09-1)

๐Ÿ“ ์—ฐ๊ด€ ํฌ์ŠคํŒ…

Github


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

1. useState์˜ ํ•ต์‹ฌ ๊ฐœ๋…

useState๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

useState๋Š” ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ **์ƒํƒœ(State)**๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” React Hook์ด๋‹ค. ์ƒํƒœ๊ฐ€ ๋ณ€ํ•˜๋ฉด React๋Š” ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ **๋ฆฌ๋ Œ๋”๋ง(Re-rendering)**ํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ UI๋ฅผ ํ™”๋ฉด์— ์ฆ‰์‹œ ๋ฐ˜์˜ํ•œ๋‹ค.

const [state, setState] = useState(initialValue);
  • state: ํ˜„์žฌ ์ƒํƒœ ๊ฐ’.
  • setState: ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜.
  • initialValue: ์ƒํƒœ์˜ ์ดˆ๊ธฐ๊ฐ’.

๐Ÿง ์™œ ์ƒํƒœ๋ฅผ '๊ฐ์ฒด'๋กœ ๊ด€๋ฆฌํ• ๊นŒ?

๋‹จ์ˆœํžˆ boolean ๊ฐ’์„ ์—ฌ๋Ÿฌ ๊ฐœ ๋งŒ๋“œ๋Š” ๋Œ€์‹ , ํ•˜๋‚˜์˜ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ(App)์—์„œ ๊ฐ์ฒด ํ˜•ํƒœ์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉด ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„์„ ํŒŒ์•…ํ•˜๊ธฐ ํ›จ์”ฌ ์ˆ˜์›”ํ•˜๋‹ค.

  • ์—ฐ๊ด€ ๋ฐ์ดํ„ฐ์˜ ๊ทธ๋ฃนํ™”: ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก(projects)๊ณผ ํ˜„์žฌ ์„ ํƒ๋œ ํ”„๋กœ์ ํŠธ(selectedProjectId)๋Š” ๋…ผ๋ฆฌ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ๋ฐ์ดํ„ฐ์ด๋‹ค. ์ด๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์œผ๋ฉด ์ƒํƒœ ๊ด€๋ฆฌ์˜ ํ๋ฆ„์ด ๋ช…ํ™•ํ•ด์ง„๋‹ค.
  • ์ƒํƒœ ์—…๋ฐ์ดํŠธ์˜ ํšจ์œจ์„ฑ: ์—ฌ๋Ÿฌ ๊ฐœ์˜ useState๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ์“ฐ๋Š” ๋Œ€์‹ , ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋งŒ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ๊ด€๋ จ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

2. ์ƒํƒœ ์„ค๊ณ„: undefined vs null ์ „๋žต

์ด๋ฒˆ ๊ตฌํ˜„์—์„œ๋Š” selectedProjectId์˜ ์ƒํƒœ๊ฐ’์— ๋”ฐ๋ผ ์•ฑ์˜ ํ˜„์žฌ "๋ชจ๋“œ"๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.

const [projectsState, setProjectsState] = useState({
  selectedProjectId: undefined, 
  projects: [] 
});
  • undefined: ์ดˆ๊ธฐ ์ƒํƒœ. ์•„๋ฌด ํ”„๋กœ์ ํŠธ๋„ ์„ ํƒ๋˜์ง€ ์•Š์•˜๊ณ , ์ถ”๊ฐ€ ์ค‘๋„ ์•„๋‹Œ ๋Œ€๊ธฐ ํ™”๋ฉด(Fallback) ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • null: 'Add Project' ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋Š” ์ž…๋ ฅ ํผ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • ID (string/number): ํŠน์ • ํ”„๋กœ์ ํŠธ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ƒ์„ธ ๋‚ด์šฉ์„ ๋ณด๊ณ  ์žˆ๋Š” ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

๋‹จ์ˆœํžˆ true/false๋งŒ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์„ธ ๊ฐ€์ง€ ์ด์ƒ์˜ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์–ด๋ ค์› ๊ฒ ์ง€๋งŒ, ์ด์ฒ˜๋Ÿผ ๊ฐ’์˜ ํƒ€์ž…์„ ๋‹ค๋ฅด๊ฒŒ ๊ฐ€์ ธ๊ฐ์œผ๋กœ์จ ํ™”๋ฉด ์ œ์–ด๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.


3. ์ƒํƒœ ๋ณ€๊ฒฝ๊ณผ ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ

์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ๋•Œ๋Š” ์ด์ „ ์ƒํƒœ(prevState)๋ฅผ ๋ณด์กดํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ด๋‹ค.

'ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ'๊ฐ€ ํ•„์š”ํ•œ ์ด์œ 

React์—์„œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ตœ์‹  ์ƒํƒœ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๊ฐ€์ ธ์™€ ๋‹ค์Œ ์ƒํƒœ๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” prevState๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์•ˆ์ „ํ•˜๋‹ค.

function handleStartAddProject() {
  setProjectsState(prevState => {
    return {
      ...prevState, // ๊ธฐ์กด์˜ projects ๋ฐฐ์—ด ๋“ฑ ์ด์ „ ์ƒํƒœ ๋ณต์‚ฌ
      selectedProjectId: null, // ์ƒˆ ํ”„๋กœ์ ํŠธ ์ž‘์„ฑ ๋ชจ๋“œ๋กœ ์ „ํ™˜
    };
  });
}

4. ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ํ†ต์‹ ๊ณผ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง

Props๋ฅผ ํ†ตํ•œ ํ•จ์ˆ˜ ์ „๋‹ฌ

์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜(handleStartAddProject)๋ฅผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜์—ฌ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋„๋ก ์—ฐ๊ฒฐํ•œ๋‹ค.

// App.jsx ๋‚ด๋ถ€
<ProjectSidebar onStartAddProject={handleStartAddProject} />
<NoProjectSelected onStartAddProject={handleStartAddProject} />

์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๋กœ์ง

์ƒํƒœ๊ฐ’์— ๋”ฐ๋ผ ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณ€์ˆ˜์— ๋‹ด์„์ง€ ๊ฒฐ์ •ํ•œ๋‹ค. if-else ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ธ๋‹ค.

let content;

if (projectsState.selectedProjectId === null) {
  content = <NewProject />;
} else if (projectsState.selectedProjectId === undefined) {
  content = <NoProjectSelected onStartAddProject={handleStartAddProject} />;
}

return (
  <main className="h-screen my-8 flex gap-8">
    <ProjectSidebar onStartAddProject={handleStartAddProject} />
    {content}
  </main>
);

5. ํ•ต์‹ฌ ์š”์•ฝ

  1. ์ƒํƒœ์˜ ์˜๋ฏธ ๋ถ„ํ™”: undefined์™€ null์„ ๊ตฌ๋ถ„ํ•˜์—ฌ ์•ฑ์˜ ๋‹ค์ค‘ ๋ชจ๋“œ(๋Œ€๊ธฐ, ์ƒ์„ฑ, ์ƒ์„ธ)๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์ œ์–ดํ•œ๋‹ค.
  2. ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ์™€ ์ „๊ฐœ ์—ฐ์‚ฐ์ž: ๊ฐ์ฒด ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ๋Š” ...prevState๋ฅผ ํ†ตํ•ด ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค.
  3. ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐํ™”: ๋ถ€๋ชจ์˜ ์ƒํƒœ ๋ณ€๊ฒฝ ํ•จ์ˆ˜๋ฅผ ์ž์‹์—๊ฒŒ ์ „๋‹ฌํ•จ์œผ๋กœ์จ UI์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•œ๋‹ค.

6. ์ฝ”๋“œ

App.jsx

import { useState } from "react";
import NewProject from "./component/NewProject";
import ProjectSidebar from "./component/ProjectSidebar";
import NoProjectSelected from "./component/NoProjectSelected.jsx";
function App() {
  const [projectsState, setProjectsState] = useState({
    selectedProjectId: undefined, // neither adding a new project nor have a project selected
    project: [],
  });

  function handleStartAddProject() {
    setProjectsState((prevState) => {
      return {
        ...prevState,
        selectedProjectId: null,
      };
    });
  }

  let content;

  if (projectsState.selectedProjectId === null) {
    content = <NewProject />;
  } else if (projectsState.selectedProjectId === undefined) {
    content = <NoProjectSelected onStartAddProject={handleStartAddProject} />;
  }

  return (
    <main className="flex flex-row h-screen gap-8 my-8">
      {/* <h1 className="my-8 text-5xl font-bold text-center">Hello World</h1>
       */}
      <ProjectSidebar onStartAddProject={handleStartAddProject} />
      {/* <NoProjectSelected onStartAddProject={handleStartAddProject} /> */}
      {content}
    </main>
  );
}

export default App;

๋ฐ๋ชจ

๋ฐ๋ชจ

  • Project๊ฐ€ Selected ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋ฉด
    • NoProjectSelected ํ™”๋ฉด
  • 'Create new project' ๋ฒ„ํŠผ์„ ํด๋ฆญ
    • selectedProjectId๊ฐ€ null : ์ƒˆํ”„๋กœ์ ํŠธ ์ถ”๊ฐ€
    • selectedProjectId๊ฐ€ {์–ด๋–ค ๊ฐ’} : {์–ด๋–ค ๊ฐ’} ํ”„๋กœ์ ํŠธ ์ƒ์„ธ ๋ณด๊ธฐ
์ตœ์šฐ์ง„ ํ”„๋กœํ•„

Woojin

๊ตฌ์กฐ์ ์œผ๋กœ ์‚ฌ๊ณ ํ•˜๊ณ , ๊ทผ๊ฑฐ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.