리덕스는 상태 관리 라이브러리이다. 리덕스를 쓰면 상태 관리를 컴포넌트 바깥에서 할 수 있다. 리덕스를 쓰기 전에는 최상단 컴포넌트에서 상태값을 관리하고 그 상태값을 props 로 자식 컴포넌트에 내려줬다. 프로젝트의 규모가 커지면 depth 가 커지고 따라서 상태 관리를 하기 복잡하다. 리덕스를 사용하면 편하게 상태를 관리할 수 있다.
root 가 있고 그 아래 2개의 컴포넌트 a, b 가 있다고 하자. a 의 자식의 자식의 자식으로 g 컴포넌트가 있다. b 에서 이벤트가 일어나서 상태값이 변하고 변한 상태값을 g 에서 사용할 경우를 예로 들어서 리덕스를 이해해보자.
g 컴포넌트는 스토어를 구독한다. 구독 과정에서 특정 함수가 스토어에 전달된다. 스토어의 상태값이 변하면 전달됐던 함수가 호출된다.
subscribe(listener)
b 컴포넌트에서 이벤트가 발생했다. 상태값을 변경하라고 스토어에게 알려줘야 한다. 이 때 dispatch 함수를 통해 액션을 스토어에 전달한다. 액션은 스토어가 상태를 변화시킬 때 참조하는 객체*이다. 객체는 type 을 필수로 가지고 이외에 diff 와 같은 optional 한 키값을 가진다. 리덕스 스토어는 액션 객체를 전달받아 '아~ state 을 action 내용처럼 변화시키면 되겠다~'고 참조한다.
dispatch(action)
// 액션 객체 생성
const increment = (diff) => ({ type: INCREMENT, diff: diff})
*굳이 액션 객체를 생성하는 이유는 액션이 생길 때마다 객체 형태로 만들기 번거롭고, 액션이 여러 파라미터를 받게 될 때 객체 형태이면 유용하기 때문이다.
리덕스 스토어 안에는 리듀서 함수가 있다. d 컴포넌트에서 dispatch 를 통해 액션을 전달 받으면 리듀서에서 전달 받은 액션 객체(의 type)에 해당하는 로직을 실행시키고, 새로운 상태값을 반환한다. 리듀서는 업뎃 로직을 정의하는 함수라고 이해하자. 리듀서는 state(현재 상태) 와 action(액션 객체) 을 파라미터로 받는다.
상태가 변화하면 g 컴포넌트가 스토어에 전달했던 listener 함수가 호출된다. 함수가 호출되면 b 컴포넌트의 이벤트로 인해 생성된 새로운 상태값이 g 컴포넌트로 내려진다. g 컴포넌트가 리렌더링된다.
const { createStore } = Redux;
const store = createStore(counter)
createStore 에는 리듀서가 들어간다. 미들웨어도 들어갈 수 있다. 미들웨어에 대해서는 나중에 알아보자.