티스토리 뷰

1. Redux / React Redux / Redux Thunk

1-1. Redux

 Redux는 전역 상태 관리를 위한 라이브러리이다. 기존에는 하나의 상태를 여러 곳에서 사용하기 위해서는 최상단의 부모 컴포넌트에서 자식 컴포넌트에게 Props로 상태를 전달해줘야했다. 만약 자식 컴포넌트가 부모 컴포넌트로부터 깊은 곳에 위치해있다면 중간에 상태를 사용하지 않는 컴포넌트에게도 Props를 전달해야하는 Prop drilling이 발생하게 된다. 리액트가 아무리 바닐라 자바스크립트보다 편하다고 해도 이렇게 수고스러운 작업이 반가울리 없다. 따라서 사람들은 모든 컴포넌트에서 전역으로 상태에 접근하기 위한 도구의 필요성을 느꼈고 여러 전역 상태 관리 라이브러리들이 등장하게 됐다.

 

Redux 기본 개념

- 액션(Action)

: 상태에 특정 변화가 필요할 때 발생시키는 것

 

- 액션 생성 함수(Action Creator)

: 파라미터를 받아 액션을 생성하는 함수

 

- 리듀서(Reducer)

: 현재의 상태와, 전달 받은 액션에 따라 새로운 상태를 만들어서 반환하는 함수

 

- 스토어(Store)

: 상태를 저장하는 장소로 보통 앱 하나에 하나의 스토어를 가지게 된다.

 

- 디스패치(Dispatch)

: 디스패치는 스토어의 내장함수 중 하나로 액션을 발생 시키는 것

 

- 구독(Subscribe)

: 액션이 디스패치 될 때 마다 등록해놓은 함수가 실행되도록 함.

 

1-2. React Redux

 React Redux는 Redux와 React를 같이 사용하기 위한 리덕스 공식 라이브러리이다. Context API처럼 최상위에 전역 상태를 선언해놓고 dispatch를 통해 상태가 변경되면 하위 컴포넌트가 모두 재렌더링 되도록 하는 방식으로 동작한다. 이 때문에 React Redux를 사용하면 따로 Subscribe 함수를 쓸 필요가 없다. 또한 useSelector, useDispatch 등의 편리한 hooks을 제공해준다.

 

1-3. Redux Thunk

 Redux Thunk는 비동기 처리를 위한 Redux Middleware 중 가장 많이 사용되는 라이브러리이다. 미들웨어는 리덕스의 액션과 스토어 사이에서 추가적인 작업을 할 수 있도록 돕는다.

 

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => (next) => (action) => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }
 
    return next(action);
  };
}
 
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
 
export default thunk;

 

 Redux Thunk는 클로저와 커링을 사용하여 필요한 인자를 받는다. 여기서 next는 다음 미들웨어가 있는 경우 다음 미들웨어를, 미들웨어가 없다면 reducer를 실행시킨다.

 

 현재까지 이해한 바에 따르면 applyMiddleware(thunk)가 적용되면 내부적으로 다음과 같이 동작할 것이다.

 

thunk({dispatch, getState})(nextMiddleware || combinedReducer)(action)

 

 Thunk란, 특정 작업을 나중에 하도록 미루기 위해서 함수 형태로 감싼 것을 말한다. 아래와 같이 'getCart' 함수를 Thunk 함수로 생성해보자. 그리고 dispatch(getCart())를 실행하면 앞서 살펴본 'thunk' 함수의 가장 마지막 action에 'getCart()'가 들어갈 것이다. 그리고 'getCart()'는 thunk 함수였기 때문에 아직도 함수 형태이다. 따라서 'createThunkMiddleware' 내에서 action의 type이 함수이므로 우리가 만든 getCart에 'dispatch'가 인자로 들어올 것이다('createThunkMiddleware' 네번째 라인). 이후 getCart가 리턴한 익명함수 로직이 실행된다. 익명함수 내부에서 실행되는 dispatch들은 인자로 객체를 받기 때문에 'createThunkMiddleware' 내에서 바로 next(action)이 실행된다. (여기서 다음 미들웨어가 수행되고 최종적으로 리듀서에 액션이 들어가게 되어 스토어에 상태가 반영된다)

 

export const getCart = () => async (dispatch: Dispatch<CartAction>) => {
  dispatch({ type: LOADING });
  try {
    const response = await axios.get(URL.CART);
    if (response.status !== STATUS_CODE.GET_SUCCESS) {
      throw new Error('장바구니 정보를 불러오는데 실패하였습니다.');
    }
 
    dispatch({ type: LOADING_SUCCESS, payload: FORMAT_DATA.CART(response.data) });
  } catch (error) {
    dispatch({ type: LOADING_FAILURE, loadingError: error });
  }
}

'웹 개발 > React' 카테고리의 다른 글

[React] 리스트와 Key  (0) 2021.06.22
React Router의 Hash Router와 Browser Router  (1) 2021.06.10
props를 변경하지 못하는 이유  (0) 2021.04.26
제어 컴포넌트와 비제어 컴포넌트  (1) 2021.04.26
JSX  (0) 2021.04.26