[React] Redux로 상태 관리하기 (기본)

@eunjios·2023년 10월 18일
1

Redux

목록 보기
1/3
post-thumbnail

Redux

React에서 Redux를 사용해서 상태 관리하기

Setting

CRA

// npx
npx create-react-app .

// npm
npm init react-app .

// yarn
yarn create react-app .

Redux 및 react-redux 설치

// npm
npm install redux react-redux

// yarn
yarn add redux react-redux

카운터 예제

0. Counter 컴포넌트 만들기

카운터 값과 더하기 빼기 버튼이 있는 컴포넌트를 만들자. 당연히 지금은 아무 동작도 하지 않는다.

component/Counter.js

const Counter = () => {
  const counter = 0;

  return (
    <div>
      <h2>{counter}</h2>
      <div>
        <button>더하기</button>
        <button>빼기</button>
      </div>
    </div>
  );
};

1. store 만들기

const store = createStore(리듀서);
const reducer = (기존상태, 액션) => {
  // 액션에 따라 새로운 상태를 반환
}

store는 위와 같이 createStore 를 사용해서 만들 수 있다. createStore 의 인자로 넘기는 리듀서는 기존 상태를 복사하여 새로운 상태를 반환한다. 여기서 주의할 점은 리듀서 함수는 반드시 기존 state 값을 직접적으로 변경해서는 안된다는 것이다. (state.counter++; 금지)

또한 리액트 앱 하나에 딱 하나의 store만 존재해야 한다. 여기서는 상태가 counter 하나 뿐이지만 복잡한 상태를 다루는 앱의 경우에도 store는 하나만 있어야 한다.


store/index.js

import { createStore } from 'redux';

const initialState = { counter: 0 };

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD': 
      return { counter: state.counter + action.value };
    case 'SUB':
      return { counter: state.counter - action.value };
    }
    default:
  	  return { ...state };
  }

const store = createStore(counterReducer);

export default store
  • initialState 로 초기값을 정해주지 않으면 초기 state가 undefined 타입이 되기 때문에 에러가 발생한다.
  • 리듀서 함수 counterReducer 는 counter 상태를 변화시키는 함수다.
  • store 를 외부 Provider의 prop으로 넘겨야 하므로 export 한다.

2. 컴포넌트에서 store의 state 접근하기

const state = useSelector(state => state);

react-redux 의 useSelector 를 사용해서 store의 특정 state에 접근할 수 있다. 콜백 함수의 반환값에 접근한다.


component/Counter.js

import { useSelector } from 'react-redux';

const Counter = () => {
  const counter = useSelector(state => state.counter);

  return (
    <div>
      <h2>{counter}</h2>
      <div>
        <button>더하기</button>
        <button>빼기</button>
      </div>
    </div>
  );
};
  • useSelector 의 콜백함수를 통해 state.counter 값에 접근하여 컴포넌트에 counter를 가져온다.

3. 컴포넌트에서 store의 action 접근하기

const dispatch = useDispatch();
dispatch( /* { 액션 객체 } */ );

react-redux 의 useDispatch 를 사용해서 store의 특정 action에 접근할 수 있다. dispatch 인자로 액션 객체를 넘기면, 리듀서에서 액션 객체의 값에 맞게 새로운 state 값을 업데이트하게 된다.


component/Counter.js

import { useSelector, useDispatch } from 'react-redux';

const Counter = () => {
  const counter = useSelector(state => state.counter);
  const dispatch = useDispatch();
  
  const addHandler = () => {
    dispatch({ type: 'ADD', value: 1 });
  };
  
  const subHandler = () => {
    dispatch({ type: 'SUB', value: 1 });
  };

  return (
    <div>
      <h2>{counter}</h2>
      <div>
        <button onClick={addHandler}>더하기</button>
        <button onClick={subHandler}>빼기</button>
      </div>
    </div>
  );
};
  • dispatchaction.typeaction.value 를 다르게 설정하면 리듀서를 통해 상태를 다르게 업데이트 할 수 있다.
  • 버튼의 onClick 에 해당하는 함수를 dispatch 를 통해 정의할 수 있다.

4. store 제공하기

<Provider store={store}>
  <App />
</Provider>

최상위 컴포넌트를 Provider 로 감싸서 store를 제공하면, 내부 컴포넌트에서 리덕스의 store를 전역적으로 사용할 수 있다.


index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

import { Provider } from 'react-redux';
import store from './store';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

References

profile
growth

0개의 댓글