[React] ๊ฐ์ฒด ์ํ๋ฅผ ํ์ฉํ ์กฐ๊ฑด๋ถ ๋ ๋๋ง ๊ตฌํ (#09-1)
- React
![[React] ๊ฐ์ฒด ์ํ๋ฅผ ํ์ฉํ ์กฐ๊ฑด๋ถ ๋ ๋๋ง ๊ตฌํ (#09-1)](https://coursework.vschool.io/content/images/size/w2000/2017/08/react-banner.png)
๐ ์ฐ๊ด ํฌ์คํ
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. ํต์ฌ ์์ฝ
- ์ํ์ ์๋ฏธ ๋ถํ:
undefined์null์ ๊ตฌ๋ถํ์ฌ ์ฑ์ ๋ค์ค ๋ชจ๋(๋๊ธฐ, ์์ฑ, ์์ธ)๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ ์ดํ๋ค. - ํจ์ํ ์
๋ฐ์ดํธ์ ์ ๊ฐ ์ฐ์ฐ์: ๊ฐ์ฒด ์ํ๋ฅผ ๋ณ๊ฒฝํ ๋๋
...prevState๋ฅผ ํตํด ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ์ ์งํด์ผ ํ๋ค. - ์ปดํฌ๋ํธ ๊ตฌ์กฐํ: ๋ถ๋ชจ์ ์ํ ๋ณ๊ฒฝ ํจ์๋ฅผ ์์์๊ฒ ์ ๋ฌํจ์ผ๋ก์จ 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๊ฐ {์ด๋ค ๊ฐ} : {์ด๋ค ๊ฐ} ํ๋ก์ ํธ ์์ธ ๋ณด๊ธฐ
KEEP READING
Related writing

Woojin
๊ตฌ์กฐ์ ์ผ๋ก ์ฌ๊ณ ํ๊ณ , ๊ทผ๊ฑฐ ์๊ฒ ๊ตฌํํ๊ธฐ ์ํด ๊ธฐ๋กํฉ๋๋ค.