카운터 구현 (프레젠테이셔널, 컨테이너 컴포넌트)

15379 단어 react reduxreact redux

프리젠테이셔널 컴포넌트 만들기

프리젠테이셔널 컴포넌터란, 리덕스 스토어에 직접적으로 접근하지 않고 필요한 값 또는 함수를 props 로만 받아와서 사용하는 컴포넌트이다.

src 디렉터리에 components 디렉터리를 만들고, 그 안에 Counter.js 파일을 다음과 같이 만든다.

Counter.js

import React from 'react';

function Counter({ number, diff, onIncrease, onDecrease, onSetDiff }) {
  const onChange = e => {
    // e.target.value 의 타입은 문자열이기 때문에 숫자로 변환해주어야 한다.
    onSetDiff(parseInt(e.target.value, 10));
  };
  return (
    <div>
      <h1>{number}</h1>
      <div>
        <input type="number" value={diff} min="1" onChange={onChange} />
        <button onClick={onIncrease}>+</button>
        <button onClick={onDecrease}>-</button>
      </div>
    </div>
  );
}

export default Counter;

프리젠테이셔널 컴포넌트에선 주로 이렇게 UI를 선언하는 것에 집중하며, 필요한 값들이나 함수는 props 로 받아와서 사용하는 형태로 구현한다.

컨테이너 컴포넌트 만들기

컨테이너 컴포넌트란, 리덕스 스토어의 상태를 조회하거나, 액션을 디스패치할 수 있는 컴포넌트를 의미한다. (액션을 디스패치 할 수 있다는 말은, 액션을 디스패치하는 함수를 만들어 프레젠테이셔널 컴포넌트에게 props 로 전달할 수 있다는 뜻이다.)

컨테이너 컴포넌트는 HTML 태그를 사용하지 않고, 다른 프리젠테이셔널 컴포넌트들을 불러와서 사용한다.

주의사항
시작 부분인 main.js 에서 props 로 스토어를 준 Provider 컴포넌트로 App 을 감싸지 않는다면, useSelector 와 useDispatch 를 사용해도 스토어에 접근할 수 없다.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { createStore } from 'redux';
import rootReducer from './modules';
import { Provider } from 'react-redux';
//
const store = createStore(rootReducer); //스토어를 만든다.
console.log(store.getState());//스토어의 상태를 확인한다.
//
ReactDOM.render(
  <Provider store={store}>
  	<App />
  </Provider>, 
  document.getElementById('root')
);

src 디렉터리에 containers 디렉터리를 만들고 CounterContainer.js 파일을 다음과 같이 생성한다.

CounterContainer.js

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

function CounterContainer() {
  // useSelector는 리덕스 스토어의 상태를 조회하는 Hook이다.
  // state의 값은 store.getState() 함수를 호출했을 때 나타나는 결과물과 동일하다.
  const { number, diff } = useSelector(state => ({
    number: state.counter.number,
    diff: state.counter.diff
  }));

  // useDispatch 는 리덕스 스토어의 dispatch 를 함수에서 사용 할 수 있게 해주는 Hook 이다.
  const dispatch = useDispatch();
  // 각 액션들을 디스패치하는 함수들을 만들었다.
  const onIncrease = () => dispatch(increase());
  const onDecrease = () => dispatch(decrease());
  const onSetDiff = diff => dispatch(setDiff(diff));

  return (
    <Counter
      // 상태와
      number={number}
      diff={diff}
      // 액션을 디스패치 하는 함수들을 props로 넣어준다.
      onIncrease={onIncrease}
      onDecrease={onDecrease}
      onSetDiff={onSetDiff}
    />
  );
}

export default CounterContainer;

이제 App 컴포넌트에서 CounterContainer 를 불러와서 렌더링한다.

App.js

import React from 'react';
import CounterContainer from './containers/CounterContainer';

function App() {
  return (
    <div>
      <CounterContainer />
    </div>
  );
}

export default App;


정상적으로 브라우저에 렌더링되는 것을 볼 수 있다.

좋은 웹페이지 즐겨찾기