프론트엔드 첫걸음

리덕스 관련 코드 작성하기 2. Hooks 사용하여 컨테이너 컴포넌트 만들기 본문

개발 공부/React

리덕스 관련 코드 작성하기 2. Hooks 사용하여 컨테이너 컴포넌트 만들기

차정 2022. 9. 6. 01:23
import Counter from '../components/Counter';
import { increase, decrease } 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);

 

위와 같이 connect를 사용하여 작성한 컨테이터 컴포넌트를  아래와 같이 축약할 수 있었다.

import Counter from '../components/Counter';
import { increase, decrease } from '../modules/counter';

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

//mapDispatchToProps생략 -> 내부적으로 bindActionCreators동작
export default connect(
  (state) => ({
    number: state.counter.number,
  }),
  { increase, decrease }
)(CounterContainer);

 

Hooks 사용하기 

위 코드는 Hooks를 사용하여 나타낼 수도 있다.

import { useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import Counter from '../components/Counter';
import { increase, decrease } from '../modules/counter';

const CounterContainer = () => {
  const number = useSelector((state) => state.counter.number);
  const dispatch = useDispatch();

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

export default CounterContainer;

connect함수를 사용하는 대신 react-redux에서 사용하는 Hooks를 사용할 수 있다.
state조회에는 useSelector를 사용하고, 액션디스패치에는 useDispatch를 사용한다.

 

useCallback으로 액션을 디스패치하는 함수를 감싸주어 감싸주어 컴포넌트 성능을 최적화 할 수 있다.
useDispatch를 사용할 때 useCallback과 함께 사용하는 습관을 들 것을 권합니다

const CounterContainer = () => {
  const number = useSelector((state) => state.counter.number);
  const dispatch = useDispatch();
  const onIncrease = useCallback(() => dispatch(increase()), [dispatch]);
  const onDecrease = useCallback(() => dispatch(decrease()), [dispatch]);

  return (
    <Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease} />
  );
};

 

Connect함수와 Hooks(useSelector, useDispatch)의 차이점

connect 함수를 사용하여 컨테이너 컴포넌트를 만든 경우, 해당 컨테이너 컴포넌트의 부모컴포넌트가 리렌더링 될때 
해당 컨테이너 컴포넌트의 props가 바뀌지 않았다면 리렌더링이 자동으로 방지되어 성능이 최적화된다.
반면 useSelector를 사용하여 state를 조회한 경우 이 최적화 작업이 자동으로 이뤄지지 않으므로 
성능 최적화를 위해서는 React.memo를 컨테이너 컴포넌트에 사용해주어야한다.

export default React.memo(CounterContainer);