[React] 컨테이너 컴포넌트 만들기

2021. 6. 9. 16:03Front-end/React

728x90
반응형

이제는 컴포넌트에서 리덕스 스토어에 접근하여 원하는 상태를 받아오고 액션도 디스패치해줄 것이다.

리덕스 스토어와 연동된 컴포넌트를 '컨테이너 컴포넌트'라고 부른다.

 

CounterContainer 만들기

import React from "react";
import Counter from "../components/Counter";

const CounterContainer = (props) => {
  return <Counter />;
};

export default CounterContainer;

✅containers/CounterContainer.js

위 컴포넌트를 리덕스와 연동하려면 react-redux에서 제공하는 connect 함수를 사용해야 한다.

 

connect 함수는 다음과 같이 사용한다.

connect(mapStateToProps, mapDispatchToProps)(연동할 컴포넌트)
  • mapStateToProps: 리덕스 스토어 안의 상태를 컴포넌트의 props로 넘겨주기 위해 설정하는 함수
  • mapDispatchToProps: 액션 생성 함수를 컴포넌트의 props로 넘겨주기 위해 사용하는 함수

 

이렇게 connect 함수를 호출하고 나면 또 다른 함수를 반환한다. 반환된 함수에 컴포넌트를 파라미터로 넣어주면 리덕스와 연동된 컴포넌트가 만들어진다. → 이를 더 쉽게 풀면 아래와 같다.

const makeContainer = connect(mapStateToProps, mapDispatchToProps);
makeContainer(타겟 컴포넌트);

 

CounterContainer에서 connect를 사용하는 코드

import React from "react";
import { connect } from "react-redux";
import Counter from "../components/Counter";

const CounterContainer = ({ number, increase, decrease }) => {
  return (
    <Counter number={number} onIncrease={increase} onDecrease={decrease} />
  );
};

const mapStateToProps = (state) => ({
  number: state.counter.number,
});
const mapDispatchToProps = (dispatch) => ({
  //임시 함수
  increase: () => {
    console.log(`increase`);
  },
  decrease: () => {
    console.log(`decrease`);
  },
});

export default connect(mapStateToProps, mapDispatchToProps)(CounterContainer);

✅containers/CounterContainer.js

mapStateToProps와 mapDispatchToProps에서 반환하는 객체 내부의 값들은 컴포넌트의 props로 전달된다.

mapStateToProps는 state를 파라미터로 받아오며, 이 값은 현재 스토어가 지니고 있는 상태를 가리킵니다.

mapDispatchToProps의 경우 store의 내장 함수 dispatch를 파라미터로 받아온다.

(현재 mapDispatchToProps에서는 진행 절차를 설명하기 위해 임시로 console.log를 사용하고 있다)

 

App에서 Counter를 CounterContainer로 교체하기

import React from "react";
import Todos from "./components/Todos";
import CounterContainer from "./containers/CounterContainer";

const App = (props) => {
  return (
    <>
      <CounterContainer number={0} />
      <hr />
      <Todos />
    </>
  );
};

export default App;

✅App.js

이렇게 하면 브라우저에서 +1, -1 버튼을 클릭하면 콘솔에 increase와 decrease가 찍히는 것을 확인할 수 있다.

 

 

console.log 대신 액션 생성 함수를 불러와서 액션 객체를 만들고 디스패치하기

import React from "react";
import { connect } from "react-redux";
import Counter from "../components/Counter";
import { decrease, increase } from "../modules/counter";

const CounterContainer = ({ number, increase, decrease }) => {
  return (
    <Counter number={number} onIncrease={increase} onDecrease={decrease} />
  );
};

const mapStateToProps = (state) => ({
  number: state.counter.number,
});
const mapDispatchToProps = (dispatch) => ({
  //임시 함수
  increase: () => {
    dispatch(increase());
  },
  decrease: () => {
    dispatch(decrease());
  },
});

export default connect(mapStateToProps, mapDispatchToProps)(CounterContainer);

✅CounterContainer.js

이제 +1 -1 버튼을 누르면 숫자가 바뀐다.

 

connect 함수를 사용할 때는 일반적으로 위 코드와 같이 mapStateToProps와 mapDispatchToProps를 미리 선언하고 사용한다. 하지만 connect 함수 내부에 익명 함수 형태로 선언해도 문제가 되지 않는다.

 

컴포넌트에서 액션을 디스패치하기 위해 각 액션 생성 함수를 호출하고 dispatch로 감싸는 작업이 번거로울 수 있다. (특히 액션 생성 함수의 개수가 많아진다면 더욱 그럴 것이다)

이와 같은 경우에는 리덕스에서 제공하는 bindActionCreators 함수를 사용하면 간편하다.

 

또는 bindActionCreators를 사용하지 않고도 작성할 수 있다.

 

TodosContainer 만들기

import React from "react";
import { connect } from "react-redux";
import Todos from "../components/Todos";
import { changeInput, insert, remove, toggle } from "../modules/todos";

const TodosContainer = ({
  input,
  todos,
  changeInput,
  insert,
  toggle,
  remove,
}) => {
  return (
    <Todos
      input={input}
      todos={todos}
      onChangeInput={changeInput}
      onInsert={insert}
      onToggle={toggle}
      onRemove={remove}
    />
  );
};

export default connect(
  ({ todos }) => ({
    input: todos.input,
    todos: todos.todos,
  }),
  {
    changeInput,
    insert,
    toggle,
    remove,
  }
)(TodosContainer);

✅TodosContainer.js

이번에는 connect안에 mapStateToProps랑 mapDispatchToProps를 사용하지 않고 익명함수 형태로 사용했다.

그리고 App 컴포넌트에서 Todos 대신에 TodosContainer를 렌더한다.

그리고 Todos 컴포넌트에서 받아온 props를 사용하도록 구현해본다.

728x90
반응형