Notice
Recent Posts
Recent Comments
Link
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

꽃 같은 인생

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

oz코딩스쿨/React&Redux

React 📌5. React의 상태 변경, 조건부 렌더링, Router📝

flo-jee 2025. 2. 12. 20:04

🚀 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;

📌 설명

  1. useState(0) → count의 초기값을 0으로 설정
  2. setCount(count + 1) → 상태 변경
  3. 상태가 변경되면 자동으로 컴포넌트가 다시 렌더링됨

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 페이지 설정