꽃 같은 인생
React 📌5. React의 상태 변경, 조건부 렌더링, Router📝 본문

🚀 React의 상태 변경 (State Update) 개념 정리 🚀
1️⃣ React에서 상태(State)란?
- *State(상태)**는 React 컴포넌트 내부에서 관리하는 변경 가능한 데이터입니다.
상태가 변경되면 자동으로 해당 컴포넌트가 다시 렌더링됩니다.
✅ React에서 State의 특징
- useState() 훅을 사용하여 선언
- 상태가 변경되면 자동으로 UI가 업데이트됨
- 직접 변경(state = newValue)할 수 없으며, setState()를 사용해야 함
2️⃣ State 변경하는 방법 (useState)
✅ 기본적인 State 변경
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default Counter;
📌 설명
- useState(0) → count의 초기값을 0으로 설정
- setCount(count + 1) → 상태 변경
- 상태가 변경되면 자동으로 컴포넌트가 다시 렌더링됨
3️⃣ State 변경 시 주의할 점
❌ State를 직접 변경하면 안 됨
function Counter() {
const [count, setCount] = useState(0);
const wrongUpdate = () => {
count = count + 1; // ❌ 직접 변경하면 UI가 업데이트되지 않음
};
return (
<div>
<h1>Count: {count}</h1>
<button onClick={wrongUpdate}>Increment</button>
</div>
);
}
✅ 올바른 방법 (setState 사용)
setCount(count + 1);
🔄 State 업데이트는 비동기적으로 작동
React에서 setState는 비동기적으로 실행됩니다.
이 때문에 여러 번 연속해서 상태를 업데이트하면 예상과 다르게 동작할 수 있습니다.
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
};
return (
<div>
<h1>Count: {count}</h1>
<button onClick={handleClick}>Increment</button>
</div>
);
}
📌 예상값: count + 3
📌 실제값: count + 1 (한 번만 증가)
🚨 이유? setState는 비동기적으로 실행되므로 여러 번 실행해도 마지막 값만 적용됨
✅ 해결 방법: 함수형 업데이트 사용
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
📌 이렇게 하면 prevCount가 최신 상태 값을 반영하기 때문에 예상대로 3씩 증가! 🎉
4️⃣ 객체 또는 배열 State 변경하기
✅ 객체 상태 변경 (useState와 Spread 연산자 사용)
function UserProfile() {
const [user, setUser] = useState({ name: "Alice", age: 25 });
const updateAge = () => {
setUser(prevUser => ({ ...prevUser, age: prevUser.age + 1 }));
};
return (
<div>
<h2>Name: {user.name}</h2>
<h2>Age: {user.age}</h2>
<button onClick={updateAge}>Increase Age</button>
</div>
);
}
📌 설명
- ...prevUser → 기존 객체 복사 후, 특정 값만 변경
🚨 주의! 직접 객체 변경하면 안 됨
user.age = user.age + 1; // ❌ 상태가 변경되지 않음
setUser(user); // ❌ React는 변경된 것을 감지하지 못함
✅ 반드시 새로운 객체를 만들어야 함!
setUser({ ...user, age: user.age + 1 });
✅ 배열 상태 변경 (map과 filter 활용)
📌 배열에서 요소 추가
function TodoList() {
const [todos, setTodos] = useState(["Learn React", "Practice Coding"]);
const addTodo = () => {
setTodos([...todos, "New Task"]); // 새로운 배열을 만들어 추가
};
return (
<div>
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
<button onClick={addTodo}>Add Task</button>
</div>
);
}
📌 배열에서 요소 삭제 (filter 사용)
const removeTodo = (index) => {
setTodos(todos.filter((_, i) => i !== index));
};
5️⃣ State 최적화 (불필요한 렌더링 방지)
✅ React.memo를 사용하여 불필요한 렌더링 방지
import React, { useState, memo } from "react";
const ChildComponent = memo(({ count }) => {
console.log("ChildComponent 렌더링됨!");
return <h1>Count: {count}</h1>;
});
function ParentComponent() {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
return (
<div>
<ChildComponent count={count} />
<button onClick={() => setCount(count + 1)}>Increment</button>
<input value={text} onChange={(e) => setText(e.target.value)} />
</div>
);
}
📌 설명
- memo()를 사용하면 props가 변경되지 않는 한 재렌더링되지 않음
- text를 변경해도 ChildComponent는 다시 렌더링되지 않음
🎯 최종 정리
개념 설명
| useState | React에서 상태를 관리하는 기본적인 방법 |
| setState | 상태를 변경하는 유일한 방법 (직접 변경 ❌) |
| 상태 변경 시 렌더링 | State가 변경되면 해당 컴포넌트가 자동으로 다시 렌더링됨 |
| 비동기적 업데이트 | setState는 비동기적으로 동작하므로 함수형 업데이트 사용 가능 |
| 객체 상태 변경 | { ...prevState, 변경할값 } 사용하여 새 객체 생성 |
| 배열 상태 변경 | map, filter, spread 연산자 활용 |
| 렌더링 최적화 | React.memo를 사용하여 불필요한 렌더링 방지 |

🎯 React의 조건부 렌더링(Conditional Rendering) 개념 정리 🎯
1️⃣ 조건부 렌더링이란?
- *조건부 렌더링(Conditional Rendering)**은 특정 조건에 따라 컴포넌트나 요소를 표시하거나 숨기는 기법입니다.
✅ 사용하는 이유
- 로그인 여부에 따라 다른 UI를 보여줄 때
- 데이터를 불러오는 중이라면 로딩 화면을 표시할 때
- 특정 조건을 만족할 때만 버튼이나 텍스트를 표시할 때
💡 쉽게 말하면?
"조건에 따라 다른 화면을 보여주기 위한 기술"
2️⃣ React에서 조건부 렌더링을 구현하는 방법
React에서는 다양한 방법으로 조건부 렌더링을 구현할 수 있습니다.
🔹 1. if문 사용 (가장 기본적인 방법)
javascript
복사편집
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
} else {
return <h1>Please sign in.</h1>;
}
}
function App() {
return <Greeting isLoggedIn={true} />;
}
export default App;
📌 설명
- isLoggedIn 값에 따라 "Welcome back!" 또는 "Please sign in."을 출력
🔹 2. 삼항 연산자 (? :)
javascript
복사편집
function Greeting({ isLoggedIn }) {
return (
<h1>{isLoggedIn ? "Welcome back!" : "Please sign in."}</h1>
);
}
function App() {
return <Greeting isLoggedIn={false} />;
}
📌 설명
- isLoggedIn이 true면 "Welcome back!", false면 "Please sign in." 출력
✅ 활용 예제: 로그인 상태에 따라 버튼 변경
javascript
복사편집
function LoginButton({ isLoggedIn, onLogin, onLogout }) {
return (
<button onClick={isLoggedIn ? onLogout : onLogin}>
{isLoggedIn ? "Logout" : "Login"}
</button>
);
}
🔹 3. && 연산자 (단일 조건)
javascript
복사편집
function Notification({ unreadMessages }) {
return (
<div>
<h1>Messages</h1>
{unreadMessages.length > 0 && <p>You have {unreadMessages.length} new messages.</p>}
</div>
);
}
📌 설명
- unreadMessages.length > 0일 때만 <p> 태그가 렌더링됨
💡 주의!
javascript
복사편집
0 && <h1>Hello</h1> // 결과: 0 (렌더링되지 않음)
📌 0은 falsy 값이라 <h1>이 렌더링되지 않고 0만 출력될 수도 있음
📌 값이 숫자일 경우 삼항 연산자(? :)를 사용하는 것이 더 안전함
🔹 4. 조건부 컴포넌트 렌더링
javascript
복사편집
function LoginPanel({ isLoggedIn }) {
if (!isLoggedIn) {
return <button>Login</button>;
}
return <UserProfile />;
}
function UserProfile() {
return <h2>User Profile</h2>;
}
📌 설명
- isLoggedIn === false이면 <button>Login</button>
- isLoggedIn === true이면 <UserProfile /> 렌더링
🔹 5. null을 반환하여 렌더링 방지
컴포넌트가 특정 조건을 만족하지 않을 때 아예 렌더링을 막을 수 있음.
javascript
복사편집
function Warning({ showWarning }) {
if (!showWarning) {
return null;
}
return <p>⚠️ Warning: Something went wrong!</p>;
}
📌 설명
- showWarning === false이면 null을 반환하여 화면에 아무것도 표시되지 않음
✅ 활용 예제
javascript
복사편집
function App() {
const [showWarning, setShowWarning] = useState(false);
return (
<div>
<button onClick={() => setShowWarning(!showWarning)}>
Toggle Warning
</button>
<Warning showWarning={showWarning} />
</div>
);
}
📌 버튼 클릭 시 경고 메시지를 표시하거나 숨김
🔹 6. switch문 활용
조건이 여러 개일 경우 switch문을 사용할 수도 있음.
javascript
복사편집
function StatusMessage({ status }) {
switch (status) {
case "loading":
return <p>Loading...</p>;
case "success":
return <p>✅ Success!</p>;
case "error":
return <p>❌ Error occurred!</p>;
default:
return null;
}
}
📌 설명
- status 값에 따라 "Loading...", "✅ Success!", "❌ Error occurred!" 중 하나를 렌더링
✅ 활용 예제
javascript
복사편집
function App() {
return <StatusMessage status="loading" />;
}
📌 "Loading..."이 출력됨
3️⃣ 조건부 렌더링 Best Practice
✅ 단순한 경우에는 && 연산자 사용
✅ true/false 값으로 UI를 변경할 때는 삼항 연산자(? :) 사용
✅ 컴포넌트를 아예 렌더링하지 않으려면 null 반환
✅ 여러 개의 조건이 있을 경우 switch문 활용
🎯 최종 정리
방법 설명 예제
| if 문 | 기본적인 조건문 | if (isLoggedIn) return <h1>Welcome</h1>; |
| 삼항 연산자 | ? :을 사용한 간결한 표현 | {isLoggedIn ? <h1>Welcome</h1> : <h1>Please sign in</h1>} |
| && 연산자 | 단일 조건 시 사용 | {unreadMessages.length > 0 && <p>You have messages.</p>} |
| null 반환 | 특정 조건에서 렌더링 방지 | {!showWarning ? null : <p>Warning!</p>} |
| switch 문 | 여러 조건이 있을 때 사용 | switch (status) { case "loading": return <p>Loading...</p>; } |

🚀 React Router 개념 정리 🚀
1️⃣ React Router란?
React Router는 React 애플리케이션에서 페이지 간 이동을 관리하는 라이브러리입니다.
✅ 왜 필요한가?
- React는 Single Page Application(SPA) 구조이므로 페이지 새로고침 없이 다른 화면을 보여줘야 함
- react-router-dom을 사용하면 URL 변경만으로 다른 페이지처럼 동작 가능
✅ 주요 기능
- 페이지 이동 (클라이언트 사이드 라우팅)
- 동적 라우트 (/user/:id)
- 중첩된 라우트 (<Outlet />)
- 페이지 이동 없이 URL만 변경 가능 (useNavigate)
2️⃣ React Router 설치
npm install react-router-dom
설치 후 react-router-dom을 import하여 사용하면 됩니다.
3️⃣ 기본 사용법
📌 1. BrowserRouter로 감싸기
BrowserRouter는 라우팅 기능을 활성화하는 최상위 컴포넌트입니다.
📌 index.js
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
📌 설명
- BrowserRouter로 <App />을 감싸서 라우팅 기능을 활성화
📌 2. 기본 라우팅 설정 (Routes, Route)
📌 App.js
import React from "react";
import { Routes, Route, Link } from "react-router-dom";
function Home() {
return <h1>🏠 Home Page</h1>;
}
function About() {
return <h1>ℹ️ About Page</h1>;
}
function App() {
return (
<div>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</div>
);
}
export default App;
📌 설명
- Link 컴포넌트를 사용하여 페이지 이동 (<a> 태그 대신 사용)
- Routes 안에 Route를 사용하여 각 URL에 대한 컴포넌트를 지정
- path="/" → Home 컴포넌트 표시
- path="/about" → About 컴포넌트 표시
4️⃣ 중첩된 라우트 (Nested Routes)
✅ 특정 페이지 내에서 하위 페이지를 만들고 싶을 때 사용
✅ Outlet을 사용하여 부모 컴포넌트 내에서 자식 컴포넌트를 렌더링 가능
📌 App.js
import { Routes, Route, Link, Outlet } from "react-router-dom";
function Dashboard() {
return (
<div>
<h1>📊 Dashboard</h1>
<nav>
<Link to="profile">Profile</Link>
<Link to="settings">Settings</Link>
</nav>
<Outlet /> {/* 하위 컴포넌트가 여기에 렌더링됨 */}
</div>
);
}
function Profile() {
return <h2>👤 User Profile</h2>;
}
function Settings() {
return <h2>⚙️ Settings</h2>;
}
function App() {
return (
<Routes>
<Route path="/" element={<h1>🏠 Home</h1>} />
<Route path="/dashboard" element={<Dashboard />}>
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
);
}
export default App;
📌 설명
- /dashboard → Dashboard 컴포넌트 표시
- /dashboard/profile → Dashboard 내부에서 Profile 컴포넌트 표시
- /dashboard/settings → Dashboard 내부에서 Settings 컴포넌트 표시
💡 Outlet이 있는 위치에 하위 컴포넌트가 렌더링됨
5️⃣ 동적 라우트 (Dynamic Routing)
✅ :id와 같은 변수를 포함한 URL 처리
✅ useParams() 훅을 사용하여 URL 파라미터 값을 가져올 수 있음
📌 App.js
import { Routes, Route, useParams } from "react-router-dom";
function UserDetail() {
let { id } = useParams(); // URL에서 id 값을 가져옴
return <h1>👤 User ID: {id}</h1>;
}
function App() {
return (
<Routes>
<Route path="/" element={<h1>🏠 Home</h1>} />
<Route path="/user/:id" element={<UserDetail />} />
</Routes>
);
}
export default App;
📌 설명
- /user/123 → UserDetail에서 id = 123을 출력
- /user/abc → id = abc 출력
6️⃣ 프로그램적으로 페이지 이동 (useNavigate)
✅ 버튼 클릭 시, 특정 페이지로 이동해야 할 때 사용
📌 App.js
import { useNavigate } from "react-router-dom";
function Home() {
const navigate = useNavigate();
return (
<div>
<h1>🏠 Home Page</h1>
<button onClick={() => navigate("/about")}>Go to About</button>
</div>
);
}
export default Home;
📌 설명
- useNavigate()를 사용하여 버튼 클릭 시 /about 페이지로 이동
✅ 이전 페이지로 이동
navigate(-1); // 이전 페이지로 이동 (뒤로 가기)
navigate(1); // 다음 페이지로 이동 (앞으로 가기)
7️⃣ 404 페이지 (Not Found)
✅ 사용자가 존재하지 않는 경로로 접근했을 때, 404 페이지를 보여줄 수 있음
📌 App.js
import { Routes, Route } from "react-router-dom";
function NotFound() {
return <h1>🚫 404 - Page Not Found</h1>;
}
function App() {
return (
<Routes>
<Route path="/" element={<h1>🏠 Home</h1>} />
<Route path="*" element={<NotFound />} />
</Routes>
);
}
export default App;
📌 설명
- path="*"을 사용하면 모든 정의되지 않은 경로에 대해 NotFound 페이지를 표시
🎯 React Router 주요 개념 정리
기능 설명
| BrowserRouter | 라우팅 기능 활성화 (최상위 컴포넌트) |
| Routes | 여러 개의 Route를 감싸는 컨테이너 |
| Route path="/" element={<Home />} | 특정 URL에 해당하는 컴포넌트 렌더링 |
| Link to="/about" | <a> 태그 대신 사용 (페이지 새로고침 방지) |
| Outlet | 중첩된 라우트에서 하위 컴포넌트를 렌더링하는 위치 지정 |
| useParams() | 동적 라우트에서 URL 변수 값 가져오기 |
| useNavigate() | 프로그래밍 방식으로 페이지 이동 |
| path="*" | 404 페이지 설정 |
'oz코딩스쿨 > React&Redux' 카테고리의 다른 글
| React&Redux ✨ React - 스타일링 🌈 (0) | 2025.02.27 |
|---|---|
| React 📌6. React 컴포넌트 생명주기, Hooks📝 (0) | 2025.02.12 |
| React 📌4. MPA와 SPA, Props와 State📝 (0) | 2025.02.12 |
| React 📌3. JSX란?📝 (0) | 2025.02.12 |
| React 📌2. React 첫걸음📝 (0) | 2025.02.12 |