Connecting the Store

Redux를 react에 사용하기위해서는 redux와 react-redux가 필요하다. 일전 JS-redux에서 구현 했었던 store를 store.js로 구현한다.

import { createStore } from "redux";

const ADD = "ADD";
const DELETE = "DELETE";

export const getAddAction = (text) => ({ type: ADD, id: Date.now(), text });
export const getDeleteAction = (id) => ({ type: DELETE, id });

const reducer = (state = [], { type, ...data }) => {
  switch (type) {
    case ADD:
      return [data, ...state];
    case DELETE:
      return state.filter(({ id }) => id !== data.id);
    default:
      return;
  }
};
const store = createStore(reducer);

export default store;

그리고 react app이 실행될 index.js에서 store.js를 불러오고 react-redux에서 Provider component를 app에 적용시켜 redux를 사용할 react 연결 작업을 마친다. 이 작업은 store라는 state 저장공간을 app에 연결시켜 app내에서 하위 component들이 store에 접급할 수 있도록 작업한 것이다.

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

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

mapStateToProps

Redux과 react를 서로 연결하는 방법으로 Provider을 사용하였다. 이번에는 store을 사용할 자식component에게 state와 dispatch를 전달해야하는 작업으로 자식 component도 store을 연결하는 작업을 해주어야 한다. 그리고 그 작업을 connect로 진행할 수 있다.

connect도 Provider와 같은 패키지에 있는 기능으로 부모 component에 연결되어 있는 store을 참조하여 현재 component의 props로 추가해주는 기능이다.

import React, { useState } from "react";
import { connect } from "react-redux";

function Home(props) {
  console.log(props);
  const [text, setText] = useState("");
  function onChange(e) {
    setText(e.target.value);
  }
  function onSubmit(e) {
    e.preventDefault();
    setText(text);
  }
  return (
    <>
      <h1>To Do</h1>
      <form onSubmit={onSubmit}>
        <input text="text" value={text} onChange={onChange}></input>
        <button>Add</button>
      </form>
      <ul></ul>
    </>
  );
}

const mapStateToProps = (state, ownProps) => ({ storeState: state });
export default connect(mapStateToProps)(Home);

즉, component에 없는 props를 connect를 통해서 자식 component prop에 store props를 추가해주는 것이다. 그럼 자식 component는 부모 component와 연결되어 있는 store의 state와 dispatch를 props로 접근하여 사용할 수 있게 된다.


mapDispatchToProps

Store의 state를 받는 mapStateToProps를 구현하였다면 store을 동작하는 mapDispatchToProps를 구현할 차례이다. State를 전달하는 방법과 비슷한 형태로 전달하되 dispatch의 경우 store dispatch 안에 구현되어 있는 기능을 사용하기 위해서 여러 property 설정으로 object를 설정한다.

import React, { useState } from "react";
import { connect } from "react-redux";
import { getAddAction, getDeleteAction } from "../store";

const Home = ({ getState, addToDo, deleteToDo }) => {
  const [text, setText] = useState("");
  function onChange(e) {
    setText(e.target.value);
  }
  function onSubmit(e) {
    e.preventDefault();
    setText("");
    addToDo(text);
  }
  return (
    <>
      <h1>To Do</h1>
      <form onSubmit={onSubmit}>
        <input text="text" value={text} onChange={onChange}></input>
        <button>Add</button>
      </form>
      <ul></ul>
    </>
  );
};
const mapStateToProps = (state, ownProps) => ({ getState: state });
const mapDispatchToProps = (dispatch, ownProps) => ({
  addToDo: (text) => dispatch(getAddAction(text)),
  deleteToDo: (id) => dispatch(getDeleteAction(id)),
});
export default connect(mapStateToProps, mapDispatchToProps)(Home);

mapDispatchToProps함수에서 인자로 받은 dispatch를 새롭게 선언한 object안에 여러 방법으로 사용되고 반환된것을 볼 수 있다. 그리고 그걸 Home component의 props로 전달하는 코드이다.

처음 mapStateToProps를 접했을 때 난해했지만, store가 연결되어 있는 Provider가 부모 component인 app에 연결된 걸 착안해서 내린 결론이, 자식 component가 store을 사용한다는 것은 부모 component store를 사용한다는 말이 되고 부모 component store에 접근하기 위해 connet를 사용하는 것으로 귀결된다. 그래서 connet의 동작 순서는 store 기능을 object 형태로 받아 props형태로 래핑하고 컬링으로 반환된 함수에 개발자가 정의한 component props에 래핑한 props를 mapping하여 store기능을 사용하게 되는거다.

컬링으로 반환된 함수는 부모 component에 접근할 수 있는 react기능을 사용하여 store의 기능을 mapping된 props에 연결하고, 연결된 props를 자식 component props에 mapping하는 작업을 하는것이다. connet는 단순히 전달받은 component에 props 기능을 연결하고 고대로 반환해서 개발자가 정의한 component이름으로 JSX를 사용하게 되는거다.