"Redux는 애플리케이션 상태를 관리하기 위한 자바스크립트 라이브러리로, 예측 가능한 상태 컨테이너를 통해 형상을 관리하는 기술을 갖고 있다.
사용자 인터페이스 구축을 위해 일반적으로 React, Angular와 같은 라이브러리와 함께 사용된다."
(출처: 위키피디아)
Redux가 제공하는 형상 관리 기술이 data가 더 효율적이고 전체적으로 이동될 수 있게 함으로서, Redux와 연관된 생태계가 활성화되고 있다.
특히, Redux를 React와 함께 사용하는 사람들이 많아지자 Redux에서 공식적으로 React-Redux라는 UI binding 라이브러리를 제공하기 시작했다.
Redux를 알기 전, 나는 React에서 state, props를 이용하여 상태 관리를 했다.
간단한 웹을 구성할 때는 state, props를 이용하여 data를 주고 받는 방식이 전혀 문제가 없었지만, 웹이 복잡해지고 고도화되면서 아래와 같은 불편함이 발생하기 시작했다.
Redux 이전에는 애플리케이션의 규모가 커짐으로 인해 양방향 데이터 흐름 패턴을 가지고 있던 Model-View-Controller(MVC) 방식에 불편함을 느끼게 되었다.
(출처: 강재영님의 블로그 )
방대한 사용자들이 방대한 데이터를 주고 받는 페이스북의 경우, MVC 패턴으로 데이터 흐름을 관리하며 크고 작은 버그를 마주했는데 이를 탈피하고자 Flux라는 새로운 아키텍처 패턴을 개발했다.
Flux는 단방향 데이터 흐름 패턴을 가지고 있다.
(출처: 강재영님의 블로그 )
위의 사진에서와 같이, View에서 Action(onClick event 등)이 일어나면 이를 Dispatcher(setState와 비슷한 hook)로 넘겨준 후,
Dispatcher를 통해 Store(상태 값을 가지고 있는 곳)를 업데이트 해주고, Store의 업데이트에 따라 View를 업데이트해준다.
모든 View는 Store를 바라보고 있기 때문에 정보가 단방향으로 전달된다.
React에서는 state값이 변경되었을 때와 props 값이 변경되었을 때, 렌더가 일어난다.
기존에 MVC 방식으로 컴포넌트를 직접적으로 연결했을 때는 몇 단계를 걸쳐 props를 전달하는 과정(props drilling)에서 필요하지 않은 component까지 렌더가 이루어지기 때문에 성능에 누수가 있다.
그러나 Flux 방식은 Store와 필요한 component를 바로 연결하여 단방향으로 데이터가 흐르게 하기 때문에 성능이 효율적이다.
순수함수: 함수가 실행되는 곳이 어디고 언제든, 외부의 상태를 변경하지 않으면서 동일한 입력값에는 동일한 결과값을 반환해야 한다.
(state, action) => nextState
(출처: 스택오버플로우 )
아직 Middleware에 대해서는 공부하지 않았기 때문에, 이를 제외하고 다룰 예정이다.
위의 Flux 부분에서 본 사진에서 Reducer 단계가 추가되었다.
Reducer는 store와 action 객체(action 함수를 통해 출력된 값)를 입력받아, 새로운 상태 값을 출력하는 순수 함수이다.
예를 들어 장바구니를 위한 reducer가 있다고 할 때 액션객체의 값에 따라 다른 로직을 처리해야하는 경우, 아래와 같이 함수를 작성할 수 있다.
// cartReducers.js
function cartReducer(state = INITIAL_STATE, action) {
switch (action.type) {
case "ADD_ITEM":
return [...state, action.payload]; // 스토어의 이전 상태에 새로운 item을 추가
case "DELETE_ITEM":
return [...action.payload]
default:
return state; // 해당 사항 없으면 이전 상태를 그대로 리턴
}
}
이 함수를 store에 저장할 때는 아래와 같이 combineReducers 메소드를 사용한다.
// store/reducer/index.js
import { combineReducers } from "redux";
import cartReducer from "./cartReducer";
export default combineReducers({ cartReducer });
useDispatch는 store의 내장 함수로 액션 객체를 전달하는 함수다. 따라서 인자로 액션 객체가 들어가야 한다.
스토어는 하나의 거대한 객체로, 모든 state 정보를 담고 있다.
createStore와 Provider 기능을 통해 아래와 같이 store 객체를 넘겨줄 수 있다.
import React from "react";
import ReactDOM from "react-dom";
import Routes from "./Routes";
import { Provider } from "react-redux";
import { createStore } from "redux";
import rootReducer from "./store/reducers";
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<Routes />
</Provider>,
document.getElementById("root")
);
React의 각 컴포넌트에서는 useSelector 메소드를 위해 store로부터 원하는 값을 가져올 수 있다.
const items = useSelector((store) => store.cartReducer);