레이블이 React 상태 관리인 게시물을 표시합니다. 모든 게시물 표시
레이블이 React 상태 관리인 게시물을 표시합니다. 모든 게시물 표시

2025년 1월 18일 토요일

15 Redux와 상태 관리: Redux의 기본 개념과 Redux Toolkit을 활용한 상태 관리

 React 애플리케이션에서 상태 관리(State Management)는 매우 중요한 부분입니다. 여러 컴포넌트 간의 상태를 일관되게 관리하고 공유하기 위해, Redux라는 상태 관리 라이브러리가 널리 사용됩니다. 이번 글에서는 Redux의 기본 개념과 함께 Redux Toolkit을 사용하여 상태 관리하는 방법에 대해 알아보겠습니다. Redux와 Redux Toolkit을 통해 상태 관리가 어떻게 효율적으로 이루어지는지 이해할 수 있습니다.

Redux, Redux Toolkit, 상태 관리, React 상태 관리, Redux 기본 개념, Redux Toolkit 사용법, createSlice, configureStore, 비동기 작업 처리, React 상태 관리 라이브러리


1. Redux의 기본 개념

Redux는 애플리케이션의 상태를 중앙에서 관리하는 라이브러리입니다. 기본적으로 **단일 스토어(Store)**를 통해 애플리케이션의 상태를 관리하며, **액션(Action)**과 **리듀서(Reducer)**를 이용해 상태를 변경합니다. Redux는 상태 변화의 흐름을 예측 가능하게 만들어주고, 복잡한 애플리케이션에서 일관된 상태 관리를 가능하게 합니다.


a. Redux의 핵심 원칙

Redux는 다음과 같은 세 가지 원칙을 따릅니다.

  1. 단일 데이터 저장소(Single Source of Truth)
    애플리케이션의 모든 상태는 단 하나의 스토어에 저장됩니다. 이를 통해 상태가 중앙에서 관리되고, 언제든지 애플리케이션의 상태를 쉽게 추적할 수 있습니다.

  2. 상태는 읽기 전용(Read-Only State)
    상태는 직접 수정할 수 없고, 오직 **액션(Action)**을 통해서만 상태를 변경할 수 있습니다. 이렇게 함으로써 상태 변경의 흐름을 명확히 할 수 있습니다.

  3. 변경은 순수 함수(Pure Function)로만 처리(Pure Function for Changes)
    상태를 변경하는 로직은 순수 함수인 **리듀서(Reducer)**에서 처리됩니다. 리듀서는 상태를 변화시키지 않고 새로운 상태를 반환합니다.

b. 기본적인 Redux 코드 구조

Redux를 사용한 애플리케이션은 보통 다음과 같은 구조를 가집니다.

  1. 액션(Action): 상태 변경을 일으킬 수 있는 이벤트를 정의합니다.
  2. 리듀서(Reducer): 액션을 처리하여 새로운 상태를 반환하는 함수입니다.
  3. 스토어(Store): 애플리케이션의 전체 상태를 저장하는 객체입니다.

// 액션 정의 const increment = () => ({ type: 'INCREMENT' }); // 리듀서 정의 const counterReducer = (state = 0, action) => { switch (action.type) { case 'INCREMENT': return state + 1; default: return state; } }; // 스토어 생성 import { createStore } from 'redux'; const store = createStore(counterReducer); // 상태 구독 store.subscribe(() => console.log(store.getState())); // 액션 디스패치 store.dispatch(increment()); // 출력: 1

위 코드는 매우 간단한 Redux의 구현 예시입니다. INCREMENT 액션을 디스패치하면, 상태가 증가하는 방식입니다.

2. Redux Toolkit을 활용한 상태 관리

Redux Toolkit은 Redux의 공식 도구로, Redux를 더 쉽게 사용할 수 있도록 도와줍니다. Redux Toolkit은 Redux의 보일러플레이트 코드(반복적인 코드)를 줄여주고, 상태 관리의 복잡성을 낮춰줍니다. Redux Toolkit을 사용하면 더욱 간단하고 직관적으로 상태를 관리할 수 있습니다.

a. Redux Toolkit 사용하기

Redux Toolkit을 사용하기 위해서는 먼저 @reduxjs/toolkit 패키지를 설치해야 합니다. 아래는 설치 명령어입니다.


npm install @reduxjs/toolkit react-redux

b. Redux Toolkit의 주요 함수

  1. configureStore: 스토어를 설정하는 함수입니다.
  2. createSlice: 상태와 액션을 함께 정의하는 함수입니다.
  3. createAsyncThunk: 비동기 작업을 처리할 때 사용하는 함수입니다.

c. Redux Toolkit으로 상태 관리하기

이제 Redux Toolkit을 사용하여 상태를 관리하는 예시를 살펴보겠습니다.


import { configureStore, createSlice } from '@reduxjs/toolkit'; // Slice 정의: 상태와 액션을 한 곳에서 관리 const counterSlice = createSlice({ name: 'counter', initialState: 0, reducers: { increment: (state) => state + 1, decrement: (state) => state - 1 } }); // 스토어 생성 const store = configureStore({ reducer: { counter: counterSlice.reducer } }); // 액션 const { increment, decrement } = counterSlice.actions; // 상태 구독 store.subscribe(() => console.log(store.getState())); // 액션 디스패치 store.dispatch(increment()); // 출력: 1 store.dispatch(decrement()); // 출력: 0

위 코드에서는 createSlice를 사용하여 incrementdecrement라는 두 가지 액션을 정의하고, 이를 통해 상태를 간편하게 변경할 수 있습니다. configureStore를 사용하여 스토어를 생성하고, 상태를 추적할 수 있습니다.

d. 비동기 작업 처리하기

Redux Toolkit에서는 비동기 작업을 쉽게 처리할 수 있도록 createAsyncThunk를 제공합니다. 예를 들어, API 호출을 통해 데이터를 가져오는 비동기 작업을 처리할 수 있습니다.


import { createSlice, createAsyncThunk, configureStore } from '@reduxjs/toolkit'; // 비동기 작업 정의 export const fetchUser = createAsyncThunk('user/fetchUser', async (userId) => { const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`); return response.json(); }); // Slice 정의 const userSlice = createSlice({ name: 'user', initialState: { user: {}, status: 'idle' }, reducers: {}, extraReducers: (builder) => { builder .addCase(fetchUser.pending, (state) => { state.status = 'loading'; }) .addCase(fetchUser.fulfilled, (state, action) => { state.status = 'succeeded'; state.user = action.payload; }) .addCase(fetchUser.rejected, (state) => { state.status = 'failed'; }); } }); // 스토어 생성 const store = configureStore({ reducer: { user: userSlice.reducer } }); // 액션 디스패치 store.dispatch(fetchUser(1));

위 예시에서는 createAsyncThunk를 사용하여 사용자 정보를 API에서 가져오는 비동기 작업을 정의했습니다. extraReducers를 통해 비동기 작업의 상태를 추적하고, 결과에 따라 상태를 업데이트합니다.

3. Redux와 Redux Toolkit의 차이점

  • Redux: 기본적인 상태 관리 기능을 제공하지만, 설정이나 액션, 리듀서 코드가 다소 복잡하고 반복적입니다.
  • Redux Toolkit: Redux의 보일러플레이트 코드를 줄여주고, 상태 관리 로직을 더 간편하게 처리할 수 있도록 도와주는 도구입니다. 특히, createSlice, configureStore, createAsyncThunk와 같은 기능을 통해 코드가 간결하고 직관적입니다.

4. 결론

ReduxRedux Toolkit은 React 애플리케이션에서 상태를 관리하는 매우 강력한 도구입니다. Redux는 중앙집중식 상태 관리로 애플리케이션의 상태를 일관되게 유지할 수 있게 도와주며, Redux Toolkit을 사용하면 복잡한 설정과 보일러플레이트 코드를 줄여 코드의 가독성과 유지보수성을 높일 수 있습니다.

초기에는 조금 복잡하게 느껴질 수 있지만, Redux와 Redux Toolkit을 활용하면 점차적으로 상태 관리의 효율성을 경험할 수 있습니다. 상태 관리가 필요한 React 애플리케이션에서 ReduxRedux Toolkit을 적극적으로 사용해보세요.

11 Context API로 상태 관리하기: Props Drilling 문제 해결 및 전역 상태 공유 방법

 

Props Drilling, Context API, 전역 상태, useContext, React 상태 관리, Redux, 상태 관리, React 컴포넌트, 상태 업데이트, React Props


1. Props Drilling 문제란?

React에서는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 props를 사용합니다. 하지만 컴포넌트의 깊이가 깊어질수록 props를 여러 단계에 걸쳐 전달해야 하는 문제가 발생하는데, 이를 Props Drilling 문제라고 합니다.

가. Props Drilling 문제 예제

import React, { useState } from "react";

function Parent() {
  const [user, setUser] = useState("홍길동");
  return <Child user={user} />;
}

function Child({ user }) {
  return <GrandChild user={user} />;
}

function GrandChild({ user }) {
  return <p>사용자 이름: {user}</p>;
}

export default Parent;

위 예제에서는 user 상태를 Parent 컴포넌트에서 생성했지만 GrandChild까지 전달하려면 Child를 거쳐야 합니다. 이런 방식은 컴포넌트 구조가 복잡해질수록 유지보수가 어려워지는 단점이 있습니다.

2. Context API를 활용한 전역 상태 공유

Context API를 사용하면 props를 단계별로 전달하지 않고도 원하는 컴포넌트에서 직접 접근할 수 있습니다.

나. Context API 기본 구조

import React, { createContext, useContext, useState } from "react";

// 1. Context 생성
const UserContext = createContext();

function App() {
  const [user, setUser] = useState("홍길동");
  return (
    <UserContext.Provider value={user}>
      <Child />
    </UserContext.Provider>
  );
}

function Child() {
  return <GrandChild />;
}

function GrandChild() {
  // 2. Context 사용
  const user = useContext(UserContext);
  return <p>사용자 이름: {user}</p>;
}

export default App;

다. Context API를 사용한 전역 상태 관리

위 코드에서는 UserContext를 생성한 후 UserContext.Provider를 통해 전역 상태를 공급합니다. 그리고 useContext(UserContext)를 사용하여 필요한 곳에서 상태를 직접 가져올 수 있습니다. 이를 통해 props를 여러 단계에 걸쳐 전달하지 않고도 데이터를 공유할 수 있습니다.

3. Context API와 Redux 비교

비교 항목Context APIRedux

사용 목적전역 상태 공유상태 관리 및 상태 변경 로직 분리
상태 업데이트useState와 함께 사용Reducer를 통해 변경
복잡성간단함설정이 필요함
성능가벼움중간 크기의 프로젝트에 적합

Context API는 간단한 전역 상태 공유에 적합하며, Redux는 상태 변화가 빈번한 대규모 애플리케이션에서 유용합니다.

4. 정리

Props Drilling 문제는 props를 깊게 전달해야 하는 경우 발생하며, 이를 해결하기 위해 Context API를 활용할 수 있습니다. useContext를 사용하면 원하는 컴포넌트에서 직접 전역 상태를 가져올 수 있어 코드가 간결해지고 유지보수가 쉬워집니다.

Context API는 비교적 간단한 프로젝트에서 전역 상태를 관리하는 데 적합하며, 프로젝트의 규모가 커질 경우 Redux 같은 상태 관리 라이브러리와 함께 사용하는 것이 좋습니다. 프로젝트의 복잡도에 맞는 적절한 상태 관리 방법을 선택하는 것이 중요합니다.

10 React에서 폼(Form) 다루기: 입력 요소의 상태 관리 및 useRef 활용

 

React 폼, 제어 컴포넌트, 비제어 컴포넌트, useState, useRef, React 상태 관리, 폼 입력, React 이벤트 처리, 폼 제출, React 렌더링



1. React에서 폼(Form)의 중요성

웹 애플리케이션에서 폼(Form)은 사용자 입력을 받아 처리하는 중요한 요소입니다. React에서는 폼을 다룰 때 제어 컴포넌트(Control Component)와 비제어 컴포넌트(Uncontrolled Component)라는 두 가지 방식이 있습니다. 이번 글에서는 입력 요소의 상태 관리와 useRef를 활용한 비제어 컴포넌트를 살펴보겠습니다.

2. 입력 요소의 상태 관리

입력 요소의 상태를 관리하는 가장 일반적인 방법은 useState를 사용하는 것입니다. useState를 활용하면 입력 값이 변경될 때마다 상태를 업데이트할 수 있습니다.

가. useState를 활용한 입력 요소 관리

import React, { useState } from "react";

function ControlledForm() {
  const [name, setName] = useState("");

  const handleChange = (event) => {
    setName(event.target.value);
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    alert(`입력된 이름: ${name}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" value={name} onChange={handleChange} />
      <button type="submit">제출</button>
    </form>
  );
}

export default ControlledForm;

위 코드에서 useState를 활용하여 name 상태를 관리하고 있으며, 입력 값이 변경될 때마다 onChange 이벤트를 통해 상태를 업데이트합니다.

3. useRef를 활용한 비제어 컴포넌트

비제어 컴포넌트는 useRef를 활용하여 직접 DOM 요소에 접근하여 값을 가져오는 방식입니다. 상태 관리를 하지 않기 때문에 불필요한 렌더링을 줄일 수 있습니다.

나. useRef를 활용한 비제어 컴포넌트 예제

import React, { useRef } from "react";

function UncontrolledForm() {
  const inputRef = useRef(null);

  const handleSubmit = (event) => {
    event.preventDefault();
    alert(`입력된 값: ${inputRef.current.value}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" ref={inputRef} />
      <button type="submit">제출</button>
    </form>
  );
}

export default UncontrolledForm;

위 코드에서 useRef를 활용하여 입력 요소에 직접 접근하고 있으며, onChange 이벤트 없이도 값을 가져올 수 있습니다.

4. 제어 컴포넌트 vs 비제어 컴포넌트

비교 항목제어 컴포넌트 (Controlled)비제어 컴포넌트 (Uncontrolled)

상태 관리useState 활용useRef 활용
렌더링 발생값 변경 시마다 리렌더링값 변경 시 리렌더링 없음
활용 예동적 검증, 실시간 입력 값 처리빠른 폼 제출, 초기값 유지

제어 컴포넌트는 입력 값이 상태에 저장되므로 입력 값 검증이나 조건부 로직 적용에 유용합니다. 반면, 비제어 컴포넌트는 입력 값을 한 번에 가져와야 할 때 유용하며, 불필요한 리렌더링을 방지할 수 있습니다.

5. 정리

React에서 폼을 다루는 방식에는 제어 컴포넌트와 비제어 컴포넌트가 있으며, 각각의 장점과 단점이 존재합니다. useState를 사용하면 입력 값을 쉽게 관리할 수 있지만, 렌더링 비용이 증가할 수 있습니다. 반면, useRef를 활용한 비제어 컴포넌트는 렌더링을 최소화할 수 있지만 값 변경을 실시간으로 반영하기 어렵습니다.

React에서 폼을 다룰 때 프로젝트의 요구 사항에 맞게 적절한 방법을 선택하는 것이 중요합니다. 앞으로의 개발에서 이 두 가지 방식을 적절히 활용하여 효율적인 폼 관리를 해보시길 바랍니다!

9 React useEffect 훅과 라이프사이클 완벽 정리

 React의 useEffect 훅은 컴포넌트의 생명주기(lifecycle)와 관련된 작업을 수행할 때 사용됩니다. 이를 활용하면 마운트, 업데이트, 언마운트 시점에서 특정 로직을 실행할 수 있습니다.


useEffect, React useEffect, React 생명주기, 컴포넌트 마운트, 업데이트 시 useEffect, API 호출 React, 타이머 설정 React, React 상태 관리, React 언마운트, useEffect 의존성 배열


1. useEffect 훅 기본 개념

useEffect는 React 컴포넌트에서 사이드 이펙트를 처리하기 위해 사용하는 훅입니다. 주로 데이터 가져오기(API 호출), DOM 업데이트, 타이머 설정과 같은 작업을 수행할 때 활용됩니다.

기본 문법

import React, { useEffect } from 'react';

function ExampleComponent() {
  useEffect(() => {
    console.log('컴포넌트가 렌더링되었습니다.');
  });

  return <div>useEffect 기본 사용법</div>;
}

위 코드는 ExampleComponent가 렌더링될 때마다 useEffect 내부의 코드가 실행됩니다.


2. 마운트, 업데이트, 언마운트 타이밍 다루기

가. 마운트 시점에서 실행

컴포넌트가 처음으로 렌더링될 때만 실행하고 싶다면 useEffect의 두 번째 인자로 빈 배열([])을 전달합니다.

useEffect(() => {
  console.log('컴포넌트가 마운트되었습니다.');
}, []); // 빈 배열을 전달하면 최초 1회만 실행됨

이렇게 하면 컴포넌트가 마운트될 때 한 번만 실행됩니다.


나. 업데이트 시점에서 실행

특정 상태(state)가 변경될 때마다 실행되도록 만들려면 useEffect의 두 번째 인자로 해당 상태를 배열에 추가합니다.

import React, { useState, useEffect } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log(`count 값이 변경됨: ${count}`);
  }, [count]); // count 값이 변경될 때마다 실행됨

  return (
    <div>
      <p>카운트: {count}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
}

이렇게 하면 count 값이 변경될 때마다 useEffect가 실행됩니다.


다. 언마운트 시점에서 실행

컴포넌트가 제거될 때(clean-up)를 수행하려면 useEffect 내부에서 return 문을 사용하여 정리(clean-up) 함수를 반환하면 됩니다.

useEffect(() => {
  console.log('컴포넌트가 마운트됨');
  return () => {
    console.log('컴포넌트가 언마운트됨');
  };
}, []);

위 코드는 컴포넌트가 마운트될 때 실행되고, 컴포넌트가 제거될 때 정리(clean-up) 함수가 실행됩니다.


3. useEffect 훅을 활용한 실전 예제

가. API 호출 예제

import React, { useState, useEffect } from 'react';

function FetchData() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then((response) => response.json())
      .then((json) => setData(json));
  }, []);

  return (

API 데이터

{JSON.stringify(data, null, 2)}
); }

위 코드는 API에서 데이터를 가져와 화면에 출력하는 간단한 예제입니다. 마운트될 때 한 번만 실행되도록 설정되었습니다.


나. 타이머 설정 예제

import React, { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds((prev) => prev + 1);
    }, 1000);

    return () => clearInterval(interval); // 언마운트 시 타이머 정리
  }, []);

  return <p>타이머: {seconds}초</p>;
}

이 코드는 컴포넌트가 마운트되면 1초마다 seconds 값을 증가시키고, 언마운트되면 타이머를 정리합니다.


4. useEffect 사용 시 주의할 점

가. 의존성 배열 사용 시 주의

  • 의존성 배열을 정확하게 설정하지 않으면 무한 루프가 발생할 수 있습니다.
useEffect(() => {
  console.log('무한 루프 발생!');
}, [Math.random()]); // 매번 새로운 값이 들어가면서 무한 실행됨

나. 불필요한 렌더링 방지

  • 불필요한 상태 변경이 발생하면 useEffect가 여러 번 실행될 수 있습니다. 이를 방지하려면 상태 변경 로직을 최적화해야 합니다.

5. 정리

React의 useEffect 훅을 활용하면 컴포넌트의 라이프사이클을 효과적으로 관리할 수 있습니다.

  1. 마운트 시 실행 → useEffect(() => {}, [])
  2. 업데이트 시 실행 → useEffect(() => {}, [state])
  3. 언마운트 시 실행 → useEffect(() => { return () => {}; }, [])

또한 API 호출, 타이머 설정 등의 다양한 기능을 처리할 수 있으며, 의존성 배열을 올바르게 설정하여 최적화하는 것이 중요합니다.

위 개념을 활용하여 React 프로젝트에서 효과적으로 상태 관리 및 비동기 작업을 처리해 보세요.

6 React 조건부 렌더링 완벽 정리: if문, 삼항 연산자, && 연산자 활용

 React에서 조건부 렌더링(Conditional Rendering)은 특정 조건에 따라 UI를 변경하는 중요한 개념입니다. 사용자가 로그인했을 때 다른 화면을 보여주거나, 데이터가 있을 때만 특정 컴포넌트를 렌더링하는 등 다양한 상황에서 활용됩니다.

React 조건부 렌더링, 삼항 연산자, && 연산자, React if문, 조건부 렌더링 예제, React 로그인 상태, React 최적화, React lazy 로딩, JSX 조건문, React 상태 관리



이번 글에서는 if문, 삼항 연산자(ternary operator), && 연산자(logical AND)를 활용한 조건부 렌더링 방법을 초보자도 쉽게 이해할 수 있도록 설명드리겠습니다.



1. React에서 조건부 렌더링이란?

조건부 렌더링은 특정 조건을 만족할 때만 특정 요소를 화면에 표시하는 기법입니다. JavaScript의 if문, 삼항 연산자, && 연산자 등을 활용하여 구현할 수 있습니다.

주요 키워드: React 조건부 렌더링, if문 렌더링, 삼항 연산자, && 연산자, JSX 조건문

React에서 조건부 렌더링을 사용하는 대표적인 예제는 다음과 같습니다.

  • 사용자가 로그인했을 때만 "로그아웃" 버튼을 표시
  • 데이터가 없을 때 "데이터가 없습니다" 메시지 표시
  • 특정 조건을 만족할 때 특정 컴포넌트만 렌더링


2. if 문을 활용한 조건부 렌더링

JavaScript에서 가장 기본적인 조건문인 if 문을 React에서도 활용할 수 있습니다.


function Greeting({ isLoggedIn }) { if (isLoggedIn) { return <h1>환영합니다! </h1>; } else { return <h1>로그인해주세요. </h1>; } } export default function App() { return <Greeting isLoggedIn={true} />; }

설명:

  • isLoggedIntrue면 "환영합니다!"를 출력하고, false면 "로그인해주세요."를 출력합니다.
  • 일반적인 if 문을 사용하여 직관적으로 조건을 설정할 수 있습니다.

하지만 JSX 내부에서 if 문을 직접 사용할 수는 없습니다. JSX에서 조건문을 직접 사용하려면 다른 방법을 활용해야 합니다.



3. 삼항 연산자(? :)를 활용한 조건부 렌더링

삼항 연산자는 JSX 내부에서 사용할 수 있는 간결한 조건문입니다.


function Greeting({ isLoggedIn }) { return ( <h1>{isLoggedIn ? '환영합니다! 😊' : '로그인해주세요. 🔑'}</h1> ); } export default function App() { return <Greeting isLoggedIn={false} />; }

설명:

  • isLoggedIn 값에 따라 삼항 연산자(? :)를 이용해 h1 태그 내부의 텍스트를 동적으로 변경합니다.
  • 삼항 연산자는 JSX 내부에서 사용할 수 있어 가독성이 좋고 코드가 짧아집니다.


4. && 연산자를 활용한 조건부 렌더링

&&(논리 AND) 연산자를 사용하면 조건이 참일 때만 특정 요소를 렌더링할 수 있습니다.


function Notification({ hasMessage }) { return ( <div> <h1>알림 센터</h1> {hasMessage && <p>새로운 메시지가 있습니다! 📩</p>} </div> ); } export default function App() { return <Notification hasMessage={true} />; }

설명:

  • hasMessagetrue일 때만 <p> 태그가 렌더링됩니다.
  • false<p> 태그 자체가 생성되지 않습니다.
  • && 연산자를 활용하면 if 문 없이 간결한 코드 작성이 가능합니다.

주의: && 연산자는 falsy한 값(false, null, undefined, 0, "")을 만나면 렌더링하지 않습니다.


 


5. 조건부 렌더링을 활용한 실전 예제

조건부 렌더링을 사용하면 로그인 상태에 따라 버튼을 다르게 표시할 수 있습니다.


로그인 상태에 따라 버튼 변경하기


function LoginButton({ isLoggedIn, onLogin, onLogout }) { return ( <button onClick={isLoggedIn ? onLogout : onLogin}> {isLoggedIn ? '로그아웃' : '로그인'} </button> ); } export default function App() { const [isLoggedIn, setIsLoggedIn] = React.useState(false); return ( <div> <h1>{isLoggedIn ? '사용자님, 환영합니다!' : '로그인해주세요.'}</h1> <LoginButton isLoggedIn={isLoggedIn} onLogin={() => setIsLoggedIn(true)} onLogout={() => setIsLoggedIn(false)} /> </div> ); }

설명:

  • useState를 사용해 로그인 상태(isLoggedIn)를 관리합니다.
  • 삼항 연산자로 버튼의 텍스트와 클릭 이벤트를 동적으로 변경합니다.
  • 로그인 상태에 따라 "환영 메시지"와 "로그인/로그아웃 버튼"이 바뀝니다.


6. 조건부 렌더링 최적화 방법

React에서는 불필요한 렌더링을 최소화하는 것이 성능 최적화에 중요합니다.


6-1. null 반환을 활용하여 요소 숨기기

컴포넌트에서 특정 조건일 때 아무것도 렌더링하지 않으려면 null을 반환하면 됩니다.


function WarningMessage({ showWarning }) { if (!showWarning) { return null; // 아무것도 렌더링하지 않음 } return <p> 경고: 잘못된 접근입니다.</p>;
}

6-2. lazy 로딩을 활용하여 무거운 컴포넌트 조건부 로딩


const HeavyComponent = React.lazy(() => import('./HeavyComponent')); function App({ isLoaded }) { return ( <div> {isLoaded && ( <React.Suspense fallback={<p>로딩 중...</p>}> <HeavyComponent /> </React.Suspense> )} </div> ); }
  • React.lazy()를 활용하면 필요한 경우에만 해당 컴포넌트를 불러와 성능을 최적화할 수 있습니다.


7. 결론


React에서 조건부 렌더링은 UI를 동적으로 변경하는 핵심 기술입니다.
if문, 삼항 연산자, && 연산자 등을 적절히 활용하면 깔끔한 코드 작성과 성능 최적화가 가능합니다.

if문 → JSX 외부에서 조건을 검사할 때 사용
삼항 연산자 → JSX 내부에서 간단한 조건부 렌더링에 적합
&& 연산자 → 조건이 true일 때만 특정 요소를 렌더링할 때 사용
최적화 기법null 반환, lazy 로딩 활용

React 프로젝트에서 조건부 렌더링을 적극 활용하여 더욱 유연하고 최적화된 UI를 만들어보세요!

4 React의 상태 관리: useState 훅으로 상태 변경과 렌더링 흐름 이해하기

 React에서 상태 관리(State management)는 UI가 어떻게 변화하는지를 제어하는 중요한 개념입니다. 컴포넌트 내에서 데이터를 다루는 방법은 매우 다양하지만, 가장 기본적이고 중요한 방법은 바로 useState 훅을 사용하는 것입니다. 이번 글에서는 useState 훅을 통해 상태를 관리하는 방법과, 상태 변경과 렌더링 흐름에 대해 쉽게 설명드리겠습니다.


React 상태 관리, React useState, React 상태 변경, React 렌더링, React 상태 관리 비동기, React 상태 흐름, React 상태 업데이트, React 컴포넌트 상태, React 상태 변경 함수


1. 상태 관리란 무엇인가요?

React에서는 컴포넌트가 데이터를 가지고, 이 데이터를 화면에 표시합니다. 이때 화면에 표시되는 내용은 상태(State)라고 하며, 사용자의 입력이나 다른 이벤트에 따라 상태가 변할 수 있습니다. 상태는 컴포넌트 내부에서 관리하며, 상태가 변경되면 React는 변경된 상태를 반영하여 UI를 다시 렌더링합니다.


2. useState 훅으로 상태 관리하기

React에서 상태를 관리하려면 useState 훅을 사용합니다. useState는 상태 값을 저장하고, 상태를 변경하는 함수도 제공합니다. useState는 함수형 컴포넌트에서만 사용할 수 있습니다.

기본 사용법


import React, { useState } from 'react'; function Counter() { // useState로 상태 선언 const [count, setCount] = useState(0); return ( <div> <p>현재 카운트: {count}</p> <button onClick={() => setCount(count + 1)}>카운트 증가</button> </div> ); } export default Counter;

위 예제에서 useState(0)count라는 상태 변수를 선언하고, 초기값을 0으로 설정합니다. setCountcount의 값을 변경하는 함수입니다. 버튼을 클릭할 때마다 setCount를 호출하여 count 값을 1 증가시키고, 변경된 값은 화면에 자동으로 렌더링됩니다.


3. 상태 변경과 렌더링 흐름

상태가 변경되면 React는 UI를 다시 렌더링합니다. React는 상태 변경을 감지하고, 해당 상태가 사용되는 부분만 다시 렌더링하여 성능을 최적화합니다. 이 과정에서 중요한 점은 상태 변경은 비동기적이라는 것입니다.


상태 변경이 비동기적인 이유

React는 상태 변경을 큐에 쌓고, 그 후에 한 번에 처리합니다. 그래서 여러 번 상태를 변경할 경우, 마지막 상태 값만 반영될 수 있습니다. 예를 들어, 아래 코드를 보면 두 번의 setCount 호출이 비동기적으로 처리되는 것을 알 수 있습니다.


import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); const increaseCount = () => { setCount(count + 1); setCount(count + 1); }; return ( <div> <p>현재 카운트: {count}</p> <button onClick={increaseCount}>카운트 두 번 증가</button> </div> ); } export default Counter;

위 코드에서 버튼을 클릭하면 setCount(count + 1)이 두 번 호출되지만, 실제로는 count 값이 한 번만 증가할 수 있습니다. 이는 상태 변경이 비동기적으로 처리되기 때문입니다. 따라서 setCount가 호출될 때, count의 최신 값을 반영하지 못합니다.

이 문제를 해결하려면, 상태 변경을 이전 상태를 바탕으로 처리할 수 있도록 해야 합니다. React는 상태를 이전 상태를 기반으로 업데이트할 수 있는 방법을 제공합니다.

이전 상태 기반으로 상태 업데이트하기


const increaseCount = () => { setCount(prevCount => prevCount + 1); setCount(prevCount => prevCount + 1); };

이 방식은 prevCount를 사용하여 항상 최신 상태값을 기반으로 업데이트되기 때문에 두 번의 setCount 호출이 모두 count를 2만큼 증가시킬 수 있습니다.


4. 상태 관리의 중요성

React에서 상태 관리는 UI의 흐름을 제어하는 핵심입니다. 사용자가 버튼을 클릭하거나 입력 값을 변경할 때, 상태가 변경되면 화면이 업데이트됩니다. 이를 통해 사용자 경험을 향상시키고, UI의 일관성을 유지할 수 있습니다. useState 훅을 잘 활용하면 상태 관리가 간편하고 직관적으로 이루어지며, 더욱 효율적인 개발이 가능합니다.


5. 결론

이번 글에서는 React의 상태 관리 개념과 useState 훅을 사용하는 방법에 대해 알아보았습니다. 상태 변경이 렌더링에 미치는 영향과 비동기적인 상태 변경 흐름을 이해하는 것이 중요합니다. 이를 통해 React 애플리케이션에서 상태를 효율적으로 관리하고, 사용자에게 빠르고 일관된 UI를 제공할 수 있습니다.

React에서 상태 관리는 필수적인 개념이므로, 기본적인 useState 사용법을 잘 익혀두고, 다양한 상황에서 이를 활용해보세요.

3 React 컴포넌트 개념: 함수형 컴포넌트와 클래스형 컴포넌트

 

React 컴포넌트, 함수형 컴포넌트, 클래스형 컴포넌트, React Props, React 재사용성, React 컴포넌트 재사용, React 상태 관리, React 생명주기, 함수형 컴포넌트 vs 클래스형 컴포넌트, React 데이터 전달


React 컴포넌트란?

React에서 **컴포넌트(Component)**는 UI를 구성하는 가장 기본적인 단위입니다. 컴포넌트를 사용하면 코드의 재사용성을 높이고, 유지보수를 쉽게 할 수 있습니다. React는 **함수형 컴포넌트(Function Component)**와 클래스형 컴포넌트(Class Component) 두 가지 방식으로 컴포넌트를 정의할 수 있습니다.


함수형 컴포넌트와 클래스형 컴포넌트


1. 함수형 컴포넌트

함수형 컴포넌트는 JavaScript 함수 형태로 정의되는 컴포넌트입니다. React 16.8 이후부터는 React Hooks가 도입되면서 함수형 컴포넌트에서도 상태(state) 관리와 생명주기(lifecycle) 기능을 사용할 수 있게 되었습니다.

import React from 'react';

function Greeting(props) {
  return <h1>안녕하세요, {props.name}님!</h1>;
}

export default Greeting;

위 코드에서 Greeting함수형 컴포넌트이며, props를 받아서 name 값을 출력하는 역할을 합니다.


2. 클래스형 컴포넌트

클래스형 컴포넌트class 문법을 사용하여 정의되며, React의 Component 클래스를 상속받아야 합니다. 클래스형 컴포넌트에서는 state를 사용할 수 있으며, 생명주기 메서드를 활용할 수 있습니다.

import React, { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>안녕하세요, {this.props.name}님!</h1>;
  }
}

export default Greeting;

함수형 컴포넌트에 비해 클래스형 컴포넌트는 문법이 다소 복잡하지만, 상태(state) 관리나 생명주기 메서드가 필요할 때 사용됩니다. 그러나 React의 최신 트렌드는 함수형 컴포넌트 + Hooks를 활용하는 방식으로 변화하고 있습니다.



Props와 컴포넌트 재사용성


1. Props란?

**Props(프로퍼티)**는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용하는 객체입니다. Props는 읽기 전용(immutable)이며, 자식 컴포넌트에서 직접 수정할 수 없습니다.

function UserProfile(props) {
  return (
    <div>
      <h2>이름: {props.name}</h2>
      <p>나이: {props.age}</p>
    </div>
  );
}

function App() {
  return <UserProfile name="김철수" age={25} />;
}

위 코드에서 UserProfile 컴포넌트는 nameage 값을 props로 전달받아 화면에 표시합니다.


2. 컴포넌트 재사용성

컴포넌트의 가장 큰 장점은 재사용성입니다. 같은 컴포넌트를 여러 곳에서 사용할 수 있으며, props를 활용하여 다양한 데이터를 표현할 수 있습니다.

function Button(props) {
  return <button style={{ backgroundColor: props.color }}>{props.label}</button>;
}

function App() {
  return (
    <div>
      <Button color="blue" label="확인" />
      <Button color="red" label="취소" />
    </div>
  );
}

위 코드에서는 Button 컴포넌트를 색상과 텍스트만 변경하여 재사용하고 있습니다.


마무리

이번 장에서는 React 컴포넌트 개념, 함수형 컴포넌트와 클래스형 컴포넌트의 차이점, props와 컴포넌트 재사용성에 대해 알아보았습니다. React에서 컴포넌트는 재사용성과 유지보수성을 높이는 핵심 요소이므로, 이를 효과적으로 활용하는 것이 중요합니다.

다음 장에서는 React의 상태(state)와 생명주기(lifecycle) 메서드에 대해 알아보겠습니다.