REACT

REACT_REDUX

zayn 2024. 11. 5. 21:42

Redux는 복잡한 애플리케이션에서 상태를 보다 체계적으로 관리할 수 있게 해주는 라이브러리입니다. 




 Redux

1. 상태 관리의 필요성과 Redux 등장 배경

주요 개념 설명
- 상태 관리의 필요성: React 애플리케이션에서 컴포넌트 간 상태가 공유되어야 할 때 props를 통해 전달하거나 Context API를 사용해 데이터를 전달합니다. 그러나 애플리케이션이 복잡해질수록 상태가 여러 컴포넌트에 걸쳐 복잡하게 얽히게 되어 관리가 어려워질 수 있습니다.
- Redux의 등장 배경: 애플리케이션 상태를 체계적으로 관리하고, 상태 변경 흐름을 명확하게 하기 위해 Redux가 등장했습니다. Redux는 단일 상태 트리로 전체 애플리케이션 상태를 관리하며, 상태 변경이 예측 가능하게끔 합니다.

사용 시나리오
- Redux는 대규모 애플리케이션에서 전역 상태가 필요할 때 사용합니다. 사용자 인증, 데이터 페칭, 다중 페이지 간의 데이터 공유가 필요한 애플리케이션에 적합합니다.




 2. Redux의 주요 개념: Action, Reducer, Store

 주요 개념 설명
- Action: 상태를 변경하기 위한 '의도'를 표현하는 객체입니다. `type` 필드를 필수로 포함하며, 추가 데이터는 `payload`라는 속성으로 전달됩니다.
- Reducer: 상태의 변화를 정의하는 순수 함수입니다. 현재 상태와 액션을 받아, 변경된 새로운 상태를 반환합니다.
- Store: 애플리케이션의 상태가 저장되는 장소입니다. 모든 상태 변경은 Store를 통해 이루어지며, 전역 상태로 사용됩니다.

사용 시나리오
- Action은 사용자의 입력 이벤트나 네트워크 응답을 통해 트리거됩니다.
- Reducer는 액션에 따라 상태가 변경되도록 정의하며, 상태 변화 로직을 중앙 집중화하여 유지보수성을 높입니다.
- Store는 애플리케이션의 모든 상태를 단일화하여 여러 컴포넌트에서 쉽게 접근하고 수정할 수 있게 합니다.

예시 코드

// Action
const increment = () => ({
    type: 'INCREMENT'
});

// Reducer
const counterReducer = (state = 0, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return state + 1;
        default:
            return state;
    }
};

// Store
import { createStore } from 'redux';
const store = createStore(counterReducer);

// 상태 구독 및 변경
store.subscribe(() => console.log(store.getState()));
store.dispatch(increment()); // 상태: 1






3. Redux Toolkit 소개 및 사용법

 주요 개념 설명
- Redux Toolkit은 Redux 설정을 단순화하고 직관적인 API를 제공합니다. `createSlice`와 같은 기능을 통해 Reducer와 Action을 한 번에 정의하고, `configureStore`를 통해 미들웨어나 Redux DevTools 설정을 쉽게 할 수 있습니다.
  
사용 시나리오
- Redux Toolkit은 Redux 설정을 빠르고 쉽게 할 수 있도록 해주기 때문에, 새로운 프로젝트에서 Redux를 빠르게 설정해야 할 때 유용합니다.

예시 코드

import { configureStore, createSlice } from '@reduxjs/toolkit';

// Slice 생성
const counterSlice = createSlice({
    name: 'counter',
    initialState: 0,
    reducers: {
        increment: state => state + 1,
        decrement: state => state - 1
    }
});

const { actions, reducer } = counterSlice;
const store = configureStore({ reducer: { counter: reducer } });

store.subscribe(() => console.log(store.getState()));
store.dispatch(actions.increment()); // 상태: 1
store.dispatch(actions.decrement()); // 상태: 0






4. Redux Thunk, 미들웨어 사용법

주요 개념 설명
- 미들웨어: Redux에서 액션이 Reducer에 도달하기 전에 가로채서 다른 작업을 할 수 있도록 도와주는 기능입니다.
- Redux Thunk: 비동기 작업을 처리할 수 있는 미들웨어로, 액션 크리에이터가 일반 객체가 아닌 함수를 반환할 수 있게 합니다. 이를 통해 비동기 API 호출을 관리할 수 있습니다.

사용 시나리오
- Redux Thunk는 비동기 데이터 페칭이나 API 호출을 수행할 때 유용합니다. 예를 들어, 서버에서 데이터를 받아와 Redux 상태에 저장해야 할 때 사용됩니다.

예시 코드

import { configureStore, createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';

// Thunk 생성
export const fetchTodos = createAsyncThunk('todos/fetch', async () => {
    const response = await fetch('https://jsonplaceholder.typicode.com/todos');
    return response.json();
});

// Slice 생성
const todosSlice = createSlice({
    name: 'todos',
    initialState: { items: [], status: 'idle' },
    reducers: {},
    extraReducers: builder => {
        builder
            .addCase(fetchTodos.pending, state => { state.status = 'loading'; })
            .addCase(fetchTodos.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.items = action.payload;
            })
            .addCase(fetchTodos.rejected, state => { state.status = 'failed'; });
    }
});

const store = configureStore({ reducer: { todos: todosSlice.reducer }, middleware: [thunk] });

store.dispatch(fetchTodos());




 5. 실습 예제: Todo 리스트를 사용한 Redux 상태 관리 구현

주요 개념 설명
이 실습에서는 Redux를 사용해 간단한 Todo 리스트 애플리케이션을 만들며, Redux의 기본적인 상태 관리 개념을 실습해봅니다.

예시 코드

1. Redux 설정

import { configureStore, createSlice } from '@reduxjs/toolkit';

const todosSlice = createSlice({
    name: 'todos',
    initialState: [],
    reducers: {
        addTodo: (state, action) => {
            state.push({ id: Date.now(), text: action.payload, completed: false });
        },
        toggleTodo: (state, action) => {
            const todo = state.find(todo => todo.id === action.payload);
            if (todo) todo.completed = !todo.completed;
        }
    }
});

const { actions, reducer } = todosSlice;
const store = configureStore({ reducer: { todos: reducer } });

export const { addTodo, toggleTodo } = actions;
export default store;



2. 컴포넌트 코드

import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addTodo, toggleTodo } from './store';

function TodoApp() {
    const [text, setText] = useState('');
    const dispatch = useDispatch();
    const todos = useSelector(state => state.todos);

    const handleAddTodo = () => {
        dispatch(addTodo(text));
        setText('');
    };

    return (
        <div>
            <h1>Todo List</h1>
            <input 
                value={text} 
                onChange={(e) => setText(e.target.value)} 
                placeholder="Add a new todo" 
            />
            <button onClick={handleAddTodo}>Add Todo</button>
            <ul>
                {todos.map(todo => (
                    <li
                        key={todo.id}
                        onClick={() => dispatch(toggleTodo(todo.id))}
                        style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
                    >
                        {todo.text}
                    </li>
                ))}
            </ul>
        </div>
    );
}

export default TodoApp;

 

'REACT' 카테고리의 다른 글

REACT Supabase  (0) 2024.11.05
React Router  (0) 2024.11.05
REACT_숙련  (0) 2024.11.05
REACT HOOK  (0) 2024.11.05
REACT의 기본구조와 스타일링  (0) 2024.11.05