본문 바로가기
TIL

11. 06. 22일차 TIL - Flux, Redux, RTK

by 눈 새 2024. 11. 6.

오늘은 제공된 강의와 챌린지반 수업을 통해 Flux와 Redux, RKT에 대해 배웠다.


1. Flux

Flux란, 단방향 데이터 흐름(unidirectional data flow)을 활용한 리액트용 애플리케이션 아키텍쳐(architecture)이다. Flux는 Facebook이 React에서 발생하는 복잡한 상태 관리를 해결하기 위하여 (React 컴포넌트 간 상태 전달, 데이터 흐름을 더 직관적이고 관리하기 쉽게) 고안하여 만들었다.

 

1) Flux Architecture의 구성 요소

다음은 Flux의 기본 요소와 그들 간의 관계를 나타낸 도식이다.

 

  • Action : 애플리케이션에서 어떤 이벤트가 발생했음을 나타내는 객체
  • Dispatcher : 발생한 Action을 받아서 다른 요소들에게 전달하는 역할을 수행
  • Store : Action의 결과로 변경된 상태를 저장하는 공간
  • View : 사용자에게 데이터를 표시하고 또 다른 Action을 트리거할 수 있는 UI

이 구조에서 데이터 흐름이 단방향으로 이루어 진다는 것을 볼 수 있다. Action이 발생하면 Dispatcher를 통해 Stroe로 전달되고, Store는 변경된 상태를 View에 반영한다. View에서 발생하는 또 다른 Action은

같은 단방향 흐름을 반복한다.

 

2) Flux와 Redux의 관계

Redux는 Flux Architecture의 철학을 따라 상태 관리 로직을 구현한 라이브러리이다. Flux가 데이터 흐름을 정의한 추상적인 패턴이라면, Redux는 이를 구현한 구체적인 솔루션이라고 할 수 있다. 즉, Redux는 Flux Architecture를 실제로 구현한 구현체이다. (Redux = Reducer + Flux)

 

3) Flux vs Redux 주요 차이점

  • Flux
    • Store : 상태와 그 상태를 업데이트하는 방법을 동시에 가지고 있음
    • Dispatcher : 상태 변경을 중앙에서 관리하고 store에 전달하는 역할을 수행
  • Redux
    • store : 오직 상태만 보관, 상태를 갱신하는 로직은 Reducer 함수가 처리
    • Dispatcher : Reducer가 상태 변경을 처리하기 때문에 별도의 Dispatcher가 필요하지 않음
    • 불변성 준수 : 상태의 불변성 유지를 권장

✔ Redux상태를 갱신하는 로직을 Reducer에 위임하고, 불변성을 지켜야 한다는 점에서 Flux와

차이가 있다.

 

* Reducer란?

Redux에서 상태 업데이트 로직을 관리하는 함수이다. 현재 상태와 액션 객체를 입력받아, 새로운 상태를 반환한다. 또한 reducer는 기존 상태를 직접 변경하지 않고, 새로운 상태 객체를 반환하는  특징을 가진다. 이 과정에서 상태는 상항 불변성을 유지하며, 액션의 종유레 따라 다른 상태 변화를 처리한다.


2. Redux란?

1) 개념

Redux란 전역 상태관리 라이브러리로서, 복잡한 애플리케이션의 상태를 효과적으로 관리하고 상태 변화의 예측 가능성을 높이며 개발자 경험을 개선하는 데 도움을 준다. 이러한 특성 덕분에 많은 개발자들이 Redux를 애플리케이션의 상태 관리를 위해 선택하여 사용하고 있다. 그렇기 때문에 프론트엔드가 꼭 알아야 할 기술 스택의 일부 중 하나이다.

2) Redux의 필요성

  • 전역 상태 관리
더보기

애플리케이션이 무거워질수록 여러 컴포넌트 간에 상태를 공유해야 할 필요성이 커진다. Redux는 모든 상태를 중앙에서 관리하여 어떤 컴포넌트에서든 같은 상태에 쉽게 접근할 수 있게 해준다.

  • 예측 가능한 상태 변화
더보기

모든 상태 변화는 액션을 통해서 이루어지기 때문에 상태 변화의 흐름을 쉽게 이해하고 추적할 수 있다.

  • 디버깅 용이성
더보기

상태 변화의 기록을 남길 수 있어, 이전 상태로 돌아가거나 상태 변화의 과정을 시각적으로 추적할 수 있다. 이를 통해 버그를 찾고 수정하는 과정이 수월해진다.

  • 비동기 작업 처리
더보기

API 호출과 같은 비동기 작업을 관리하기 쉽다. Redux는 미들웨어를 통해 비동기 액션을 처리할 수 있어 복잡한 상태 관리 로직을 간소화 할 수 있다.

  • 일관성 있는 데이터 흐름
더보기

Redux는 상태와 액션의 흐름을 일관되게 유지한다. 이를 통해 애플리케이션의 데이터 흐름을 명확하게 이해할 수 있으며 코드의 가독성이 높아진다.

  • 확장성
더보기

애플리케이션이 커지더라도 Redux를 통해 상태 관리를 유지할 수 있다. 새로운 기능을 추가할 때 기존 상태 구조를 변경할 필요 없이 새로운 액션과 reducuer를 추가하면 된다.


3. Redux 설정하기

Redux를 사용하기 위해서는 여러 단계의 설정이 필요하다.

 

1) Redux 및 관련 라이브러리 설치

React에서 Redux를 사용하기 위해서는 2개의 패키지를 설치해야 한다. vscode 터미널에서 아래 명령어를 입력해서 2개의 패키지를 설치한다. react-redux 라는 패키지는 redux를 react에서 사용할 수 있도록 서로 연결시켜주는 패키지이다.

yarn add redux react-redux

# 아래와 같은 의미
yarn add redux
yarn add react-redux

 

2) Store 생성

 

Store는 App의 상태를 관리하는 객체이다. 스토어를 생성하기 위해 createStore 함수를 사용한다.

// src/store.js
import { createStore } from 'redux';
import rootReducer from './reducers'; // 리듀서를 가져옵니다.

const store = createStore(rootReducer);

export default store;

 

3) Reducer 작성

Reducer는 상태 변화를 처리하는 함수이다. 기본 상태와 액션에 따라 새로운 상태를 반환한다.

// src/reducers/index.js
const initialState = {
    count: 0,
};

const counterReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return { ...state, count: state.count + 1 };
        case 'DECREMENT':
            return { ...state, count: state.count - 1 };
        default:
            return state;
    }
};

export default counterReducer;

 

4) 액션 작성

액션은 상태 변화를 설명하는 객체이다. 액션 생성 함수를 작성하여 액션을 생성한다.

// src/actions/index.js
export const increment = () => ({
    type: 'INCREMENT',
});

export const decrement = () => ({
    type: 'DECREMENT',
});

 

5) React 컴포넌트에서 Readux 사용

제작한 store를 react 애플리케이션에 연결한다. Provider 컴포넌트를 사용하여 store를 하위 컴포넌트에 전달한다.

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
);

 

6) Redux 상태와 액션 사용

React 컴포넌트에서 Redux 상태를 사용하려면 useSelector와 useDispatch 훅을 사용한다.

// src/App.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './actions';

const App = () => {
    const count = useSelector((state) => state.count); // 상태를 가져옵니다.
    const dispatch = useDispatch(); // 액션을 디스패치하는 함수입니다.

    return (
        <div>
            <h1>Count: {count}</h1>
            <button onClick={() => dispatch(increment())}>Increment</button>
            <button onClick={() => dispatch(decrement())}>Decrement</button>
        </div>
    );
};

export default App;

4. RTK

RTK(Redux Toolkit)은 현재 Redux 로직을 작성할 때 권장되는 방법으로 Redux의 복잡성을 줄이고 개발 효율성을 높이기 위해 만들어졌다.

 

* 보일러플레이트 코드(Boilerplate Code)란?

최소한의 변경으로 여러 곳에서 재사용되며, 반복적으로 비슷한 형태를 띄는 코드를 뜻한다.

 

RTK를 통해 개발자는 불필요한 보일러플레이트 코드를 줄이고, 상태 관리 로직을 더욱 간결하게 작성할 수 있다. RTK는 기본적으로 Redux의 코어 라이브러리를 포함하고 있어 별도의 설정 없이도 사용할 수 있다.

 

1) Redux Toolkit 코드

  • Reducer 작성
    • createSlice를 사용하여 reducer와 action을 한 번에 정의할 수 있다.
더보기
// src/features/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

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

export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
  • Store 설정
    • configureStore 함수를 사용하여 Store를 생성한다.
더보기
// src/store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './features/counterSlice';

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

export default store;
  • React 컴포넌트에서 Redux 사용
    • useSelectoruseDispatch 훅을 사용하여 상태를 가져오고 액션을 디스패치한다.
더보기
// src/App.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './features/counterSlice';

const App = () => {
    const count = useSelector((state) => state.counter.value);
    const dispatch = useDispatch();

    return (
        <div>
            <h1>Count: {count}</h1>
            <button onClick={() => dispatch(increment())}>Increment</button>
            <button onClick={() => dispatch(decrement())}>Decrement</button>
        </div>
    );
};

export default App;
  • Store를 React 애플리케이션에 연결
    • Provider컴포넌트를 사용하여 Store를 App에 연결한다
더보기
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
);

 

2) 사용하는 이유

  • 간편한 스토어 설정
더보기

configureStore : Redux 스토어를 손쉽게 설정할 수 있는 함수로, 미들웨어, 개발자 도구, reducer를 자동으로 설정해준다. 기본적으로 Redux Thunk가 포함되어 있어 비동기 작업을 쉽게 처리할 수 있다.

  • 슬라이드 (Slice)
더보기

createSlice : 상태와 reducer를 함께 정읳라 수 있는 기능이다. slice는 상태의 초기값과 reducer를 포함하며, 액션 생성 함수도 자동으로 생선된다. → 상태와 관련된 모든 로직을 하나의 파일에서 관리할 수 있어 코드의 가독성과 유지보수성이 향상된다.

  • 불변성 관리
더보기

RTK는 Immer 라이브러리를 사용하여 불변성을 쉽게 관리한다.  reducer에서 상태를 직접 변경하는 것처럼 작성할 수 있지만, 실제로는 불변 객체를 생성하여 안전하게 상태를 업데이트한다.

  • 비동기 작업 처리
더보기

createAsyncThunk: 비동기 작업을 처리하기 위한 액션 생성 함수를 쉽게 만들 수 있다. API 호출과 같은 비동기 작업을 처리할 때 유용하며, 각 단계(대기, 성공, 실패)에 대한 액션이 자동으로 생성된다.

  • 개발자 도구 지원
더보기

RTK는 Redux DevTools와의 통합을 자동으로 지원하여, 상태 변화와 액션을 쉽게 추적하고 디버깅할 수 있다.

  • 미들웨어 지원
더보기

기본적으로 Redux Thunk가 포함되어 있으며, 추가 미들웨어도 쉽게 설정할 수 있습니다. 필요에 따라 다른 미들웨어를 추가하여 확장할 수 있다.

  • 타입스크립트 지원
더보기

RTK는 타입스크립트와의 호환성을 염두에 두고 설계되었으며, 타입을 자동으로 추론하여 안전하게 사용할 수 있다.

  • 유리틸티 함수
더보기

RTK는 여러 유틸리티 함수를 제공하여 상태 관리와 관련된 작업을 쉽게 수행할 수 있다. 

  • 코드 분할 및 재사용성
더보기

슬라이스를 통해 상태와 리듀서를 모듈화하여 코드의 재사용성을 높일 수 있습니다. 필요할 때 슬라이스를 가져와서 사용할 수 있습니다.

 

Redux Toolkit은 Redux의 복잡성을 줄이고더 간편하고 효율적으로 상태 관리를 할 수 있도록 도와주는 여러 기능을 제공합니다. 주요 기능으로는 간편한 스토어 설정슬라이스불변성 관리비동기 작업 처리개발자 도구 지원 등이 있다.


5. Context vs Redux

  • Redux 작동 모습

  • Context 작동 모습

1) 목적과 사용 용도

  • Redux
    • Redux는 복잡한 애플리케이션에서의 전역 상태 관리를 위해 설계된 라이브러리이다.
    • 상태의 예측 가능성일관성을 유지하며, 중첩된 컴포넌트 구조에서도 상태를 쉽게 공유할 수 있도록 돕는다.
    • 애플리케이션의 전역 상태를 관리하고, 액션과 리듀서를 통해 상태 변화를 명확하게 정의한다.
  • Context API
    • Context API는 React에서 전역 데이터를 공유하기 위한 기본적인 방법이다.
    • 주로 테마, 사용자 인증, 언어 설정, 등 비교적 간단한 상태를 관리하는 데 사용된다.
    • Context는 컴포넌트 트리 내에서 데이터를 전달하는 방법을 제공하지만, 상태 관리에 대한 복잡한 로직은 포함되어 있지 않는다.

 

2) 상태 관리의 복잡성

  • Redux
    • Redux는 상태 관리를 위한 다양한 기능을 제공한다.
    • 스토어, 액션, 리듀서, 미들웨어, 등으로 구성되어 있어 상태 변화의 흐름을 명확하게 추적할 수 있다.
    • 비동기 작업 처리, 상태의 시간여행 디버깅, 미들웨어를 통한 확장 등 복잡한 상태 관리가 필요한 경우 유용하다.
  • Context API
    • Context는 기본적으로 상태를 전달하는 기능만 제공한다.
    • 상태 관리는 useState나 useReducer를 통해 이루어진다.
    • 복잡한 상태 변화 로직을 구현하기 위해서는 추가적인 코드가 필요하다.
    • 상태 업데이트가 자주 발생하는 경우에 사용하면 성능 저하가 발생할 수 있다.

* Context는 상태관리 도구가 아니다 ⁉

더보기

상태관리는 아래 3가지 조건을 충족해야한다.

  • 초기 값을 저장한다
  • 현재 값을 읽을 수 있다.
  • 값 업데이트가 가능하다.

하지만  Context는 이러한 조건을 충족시키지 못하기 때문에 상태관리 도구라고 볼 수 없다.

 

3) 성능

  • Redux
    • Redux는 상태 변화에 따라 필요한 컴포넌트만 리렌더링하도록 최적화되어 있다. 이를 통해 성능이 향상된다.
    • Redux 개발 도구를 통해 상ㅌ태 변화와 액션을 쉽게 추적하고 디버깅할 수 있다.
  • Context API
    • Context를 사용할 경우, 제공하는 값이 변경되면 해당 값을 사용하는 모든 컴포넌트가 리렌더링된다.
    • 때문에 작은 규모의 애플리케이션이나 특정한 데이터만 전달할 때 사용하는 것이 좋다.
    • 또는 그만큼 설계를 잘해야 한다. (적절하게 Context로 묶어주어야 한다.)

 

4) 사용의 용이성

  • Redux
    • Redux는 설정과 구조가 다소 복잡할 수 있으며, 초기 학습 곡선이 필요하다.
    • 또한 복잡한 애플리케이션에 적합하다.
  • Context API
    • Context는 React의 기본 기능으로 설정이 간단하고 바로 사용할 수 있다.
    • 작은 애플리케이션이나 간단한 상태 관리에 적합하다.

Q. 그러면 우리는 Redux 혹은 비슷한 전역상태관리를 항상 사용해야할까?

 만약 그랬다면 Context API에 대해 배우지 않았을 것이다. 즉, Context API 만의 장점이 존재한다는 뜻이다.

 

▼ Context API 만의 장점

1) 간단한 설정과 구조

  • Context API는 설정이 간단하고, 추가적인 라이브러리 없이 바로 사용할 수 있다.
  • 그래서 작은 규모의 프로젝트나 특정 컴포넌트들 간의 데이터 공유에는 매우 유용하다.
  • 간단한 데이터나 기능을 전달할 때는 Redux를 사용할 필요 없이 Context만으로도 충분히 깔끔한 코드 구조를 유지할 수 있다.

2) 여러 개의 Context 사용 가능

  • Context는 여러 개를 생성해서 독립적으로 사용할 수 있다.
  • 예를 들어 테마 설정과 사용자 정보를 각각 다른 Context로 관리할 수 있어 특정 트리에 필요한 데이터만을 전달할 수 있다.
  • 즉, 모듈화에 유리하다.
  •  Redux처럼 중앙에서 모든 상태를 관리하지 않더라도 필요에 따라 데이터 흐름을 최적화할 수 있다.

3) 작은 프로젝트에 적합

  • 작은 프로젝트에서 Context를 사용하면 코드를 훨씬 단순하게 유지할 수 있다.
  • Redux는 설정이 다소 복잡하고 불필요한 보일러플레이트가 많아질 수 있지만 Context는 추가적인 코드가 거의 필요 없어서 코드량을 줄이고 유지보수를 쉽게 할 수 있다.

4) 부담 없는 학습 곡선

  • Redux는 Flux Architecture와 같은 개념을 먼저 이해해야 하고 설정 과정도 복잡할 수 있으나 Context는 리액트의 기본 개념에 가깝다.
  • 따라서 Context는 초보자에게도 쉽게 접근할 수 있는 상태 전달 방식이다.

5) 부분적인 성능 최적화 가능

  • 특정 Context에서만 업데이트가 필요할 때 그 Context가 사용되는 컴포넌트만 감싸면 된다.
  • Context는 직접 데이터를 전달하기 때문에, 불필요한 전역 상태 관리를 줄이고 트리 구조에 따라 필요한 컴포넌트만 렌더링 할 수 있다.

Redux복잡한 애플리케이션의 전역 상태 관리를 위해 설계된 라이브러리로 예측 가능한 상태 변화와 디버깅 기능을 제공한다.

✔ Context API는 React의 기본 기능으로 간단한 전역 데이터 공유를 위한 방법이지만, 복잡한 상태 관리에는 적합하지 않는다.

따라서 두 도구는 사용자의 필요에 따라 적절히 선택하여 사용할 수 있다.


★ 22일차 소감

 

오늘은 React 숙련 주차 과제에 대한 안내를 받았고 복습을 하며 챌린지반 수업에 참여하였다ㅎㅎ 정규 강의 시간에는 Redux와 Flux에 대한 개념을 배웠고 이후 미니 세미나를 통해 전날 예습한 리액트의 조건부 렌더링에 대해 복습할 수 있었다. 제공된 강의로만 학습하려니 Redux가 너무 이해가 되지 않았는데 이강민 튜터님의 설명을 통해 Redux가 무엇인지 조금은 알 수 있게 되었다고 생각한다. 확실히 학습에 도움이 되었다. 또한 세미나를 통해 이전에 알지 못했던 내용을 추가적으로 알 수 있었다. AND 연산자를 사용하여 조건부 렌더링을 할 경우에 AND연산자의 좌항 값이 falsy한 값이라면 사용자가 원하는 값이 리턴되는 것이 아닌 입력한 falsy한 값이 리턴된다는 것이다. 혼자서 공부했다면 이러한 부분까지 찾기 힘들었을 것 같다. 챌린저반으로 옮기길 정말 잘했다는 생각이 든다. 앞으로도 열심히 그리고 성실하게 공부하여 좋은 개발자로 성장하고 싶다.