완성된 소스코드 : https://github.com/leaveittogod0123/ReactLab/tree/master/Contact

이전 작업들은 redux를 써보기 위해서 틀을 구성한 것입니다.

현재 컴포넌트를 나열해보면

  • Contact - 연락처 데이터를 갖고 있으며 아래 세 개의 컴포넌트에게 props를 전달하는 Smart Component입니다.
    나머지는 컴포넌트는 다 Dumb Component입니다.
  • ContactCreate - 연락처를 추가하는 컴포넌트이고, props를 받아서 메서드를 호출합니다.
  • ContactDetails - 선택된 연락처를 수정 혹은 삭제를 할 수 있는 컴포넌트이며, 마찬가지로 props를 전달받아서 메서드를 호출합니다.
  • ContactInfo - props로 전달받은 데이터를 보여주는 컴포넌트입니다.

Smart, Dumb Component 구조는 redux를 사용하는 프로젝트에서 사용되는 용어입니다. Smart Component는 redux와 연관되어있습니다.


이전 블로그에 구현된 틀이 다 완성되었다는 가정하에 진행합니다.

작업할 내용

기존 Contact앱에 Redux를 붙일겁니다.
기존에 멍청한 컴포넌트로 props로 내려줘서 스마트 컴포넌트에서 state 변경시키는 일명 '올려치기'가 아닌 각각의 component에서 dispatch 해주는 방식입니다.

일단은 따라해보면서 연락처앱에 redux를 도입하고, 이후에 자세하게 알아보도록 할 것입니다.

설치 및 준비

yarn add -D redux react-redux

/src/actions/index.js

/src/reducers/index.js

이렇게 미리 설치할 라이브러리 다운받고, 파일을 만들어줍니다.

액션정의

/src/actions/index.js를 다음과 같이 바꿔줍니다.
액션을 정의해줍니다.
액션 이름을 상수로 정의하고, 액션 타입과, 액션에 필요한 변수들로 객체를 정의합니다.

/src/reducers/index.js 에 초기 상태와 reducer들을 정의해줍니다.
실질적으로 액션이 발생했을때 어떤일을 할지 정의했습니다.
연락처 추가, 수정, 제거, 선택 등의 기능을 할 코드들이 들어갑니다.

/src/index.js를 다음과 같이 변경해줍니다.
리덕스에서 관리할 상태를 저장할 store를 만들어줍니다!

import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import App from "./components/App";
import manageContact from "./reducers";

const store = createStore(manageContact);

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

/src/component/ContactDetails에서 dispatch할 메서드를 기록해줍니다.
원래는 Contact에서 onRemove를 props로 내려줘서 실행했지만
이제는 action에 기록해놓은 메서드를 사용합니다.

새로운 코드들이 있는데 일단은 받아들입니다. 정상적으로 동작하니까요.
dispatch가 하는 일은 핸들러입니다! 그리고 reducer에 이벤트 핸들러처럼 할일을 정의해뒀습니다.
reducer에 정의한 함수를 dispatch의 인자로 넣어줍니다!


import { connect } from "react-redux";
import { removeContact } from "../actions";

...
const mapDispatchToProps = (dispatch) => {
  return {
    onRemove: () => dispatch(removeContact()),
  };
};

const mapStateToProps = (state) => {
  return state;
};
ContactDetails = connect(mapStateToProps, mapDispatchToProps)(ContactDetails);

mapDispatchToProps는 reducer에 정의해둔 핸들러를 props로 매핑해준다로 이해했습니다.

mapStateToProps는 redux에서 관리하는 상태를 props로 매핑해준다로 이해했습니다.

ContactDetails = connect(mapStateToProps, mapDispatchToProps)(ContactDetails);

이 코드가 이해가 안되신다면 React HOC로 공식문서에서 공부하시면 이해가 되실겁니다.
레퍼런스 : HOC - Reactjs

리덕수 후기

  • 컴포넌트에 덥지덥지 붙였던 props들이 없어졌습니다.
    리덕스에서 상태를 관리하기 때문에 상태를 변경할 컴포넌트에서 dispatch를 호출해줍니다!
  • 일관된 데이터 흐름!
    dispatch가 호출되면 액션에 정의된 타입에 따라 reducer에 정의된 핸들러가 동작하여 상태를 변경합니다. 일관된 흐름으로 중첩된 컴포넌트가 많아져도 데이터가 흘러가는 길은 정해져 있습니다!

A picture is worth a thousand words !

image.png
출처 : Redux와 미들웨어(thunk, saga) - 이소영

  • 물론 모든 상태를 redux에서 관리하지 않습니다.
    단일 컴포넌트에서 관리하는 상태(변수)는 굳이 redux에서 관리하지 않았습니다.