리덕스(Redux)는 자바스크립트 어플리케이션을 위한 예측 가능한(predictable) 상태(state) 관리 컨테이너이다. 리액트에서는 클래스 컴포넌트 안에서 상태 관리가 이루어지며, 자식 컴포넌트 간에 데이터를 주고 받을 때 부모 컴포넌트를 통해야 한다. 그러나 이러한 방식은 자식 컴포넌트가 많아질수록 상태 관리가 매우 복잡해질 수 있다는 문제가 있다. 이러한 문제를 해결하기 위한 것이 바로 상태 관리 라이브러리인 리덕스이다. 참고로 리덕스는 리액트의 하위 라이브러리가 아니며 리액트 없이도 사용할 수 있는 라이브러리이다. 리덕스에는 다음과 같은 3가지 원칙이 있다.
- 동일한 데이터는 같은 곳에서 데이터를 가져옴(Single source of truth).
- 상태는 직접 변경할 수 없음(State is read-only). 리액트에서는 setState메소드 활용, 리덕스에서는 Action객체 활용.
- 리듀서에서 변경은 순수 함수로만 가능함(Changes are made with pure functions).
상태가 관리되는 오직 하나의 공간으로, 컴포넌트와 별개로 Store에 상태를 두고 컴포넌트에서 상태가 필요할 때 Store에 접근하여 정보를 가져올 수 있다.
Action은 자바스크립트 객체로, type을 비롯한 다양한 데이터를 담고 있다. Action객체는 Store에게 어플리케이션의 데이터(a payload of information)를 운반하는 역할을 한다. type을 꼭 지정해줘야 한다.
export const addToCart = (itemId) => {
return {
type: ADD_TO_CART,
payload: {
quantity: 1,
itemId
}
}
}
Dispatch는 Action을 전달하는 메소드이다. Dispatch의 전달인자로 Action 객체가 전달된다. Action객체가 Dispatch에게 전달되면 Dispatch는 Reducer를 호출하여 새로운 상태를 생성한다.
dispatch(addToCart(item.id))
이미지 출처: codestates urclass
리듀서(Reducer)는 현재 상태와 Action을 이용하여 다음 상태를 만들어내는 역할을 하며 항상 immutable하게 작동하는 순수 함수이다. state(이전 상태)와 action 두 가지를 파라미터로 받는다. 여기서 중요한 것은 Redux의 state 업데이트는 immutable한 방식으로 변경해야 한다는 것이다. 즉 기존 state를 변경하는 것이 아니라 Object.assign메소드를 사용하여 빈 객체를 복제하는 방식으로 state를 변경해줘야 한다.
const itemReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_TO_CART:
return Object.assign({}, state, {
cartItems: [...state.cartItems, action.payload]
})
}
}
Flux는 Facebook에서 클라이언트-사이드 웹 어플리케이션을 만들기 위해 사용하는 어플리케이션 아키텍쳐다. 단방향 데이터 흐름을 활용해 뷰 컴포넌트를 구성하는 React를 보완하는 역할을 한다. Flux 어플리케이션은 Dispatcher, Stores, Views(React 컴포넌트)로 구성되어 있으며, 데이터는 단방향으로 흐른다.
이미지 출처: https://facebook.github.io/flux/docs/in-depth-overview/
- 상태를 예측 가능하게 만들어주며 상태의 이력(history) 관리에 용이하다. Reducer는 순수함수이기 때문에 다음 상태를 쉽게 예측할 수 있다.
- 유지 보수가 용이하다.
- 디버깅에 유리하다. Action과 State에 log를 기록하면 Action이 발생했을 때 어떤 일이 일어났는지 추적할 수 있다.
- 순수함수를 사용하기 때문에 테스트를 붙이기 쉽다.
- 어떠한 컴포넌트도 어떤 상태든 접근이 가능하다.
- 직렬화(Serialize) 후 서버 등으로 전송하기 쉽다.