본문 바로가기

클라이언트/React
[리액트(React)] 리덕스(Redux)

// 리덕스, Redux

- redux에 대해서는 이전 글에서 작성했기 때문에 이번에는 리액트에서 사용하는 redux에 대해 정리할 예정이다.

- 참고: https://sorrel012.tistory.com/387

 

[자바스크립트(JavaScript)] 리덕스(Redux)

// 리덕스, Redux - Cross-Component나 App-Wide 상태 관리 라이브러리 // Cross-Component State - 여러 컴포넌트에 영향을 미치는 state ~ 모달창 open / close // App-Wide State - 애플리케이션 전체에 영향을 미치는 state

sorrel012.tistory.com


1. redux, react-redux 설치

npm install redux react-redux

2. 저장소 생성

import { createStore } from 'redux';

const 저장소명 = createStore();

3. Reducer 함수 추가

const reducer함수명 = (state = 기본값, action) => {
  return {
  };
}


- 기존 state, action 2개의 parameter를 받는다.

- 새로운 상태 객체를 return 한다. (이론적으로는 다른 형태로도 가능하지만, 실제로는 객체 return)


4. 저장소에 reducer 함수 전달

import { createStore } from 'redux';

const 저장소명 = createStore(reducer함수명);

5. 컴포넌트에서 사용할 수 있게 저장소 export

 

import { createStore } from 'redux';

const 저장소명 = createStore(reducer함수명);
export default 저장소명;

6. index.js 파일에 저장소를 import 한다.

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

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


- 모든 컴포넌트에서 사용하기 위에 컴포넌트 트리의 최상단에 위치하는 index.js 파일에 수정·추가한다.


7. 사용하고자 하는 컴포넌트에서 custom hook을 import 한다.

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


- useStore hook도 사용할 수 있지만, 저장소가 관리하는 state를 우리가 자동으로 선택할 수 있어 useSelector hook이 더 편리하다.

- useDispatch hook으로 action을 dispatch한다.


7. useSelector로 state를 선택한다.

const 변수명 = useSelector((state) => state.원하는data명);


- 저장소의 state가 변경되면 자동으로 컴포넌트 함수가 재실행되기 때문에 최신의 state를 얻을 수 있다.


7. 사용하고자 하는 컴포넌트에서 useDispatch hook으로 action을 dispatch한다.

const dispatch = useDispatch();

const 함수명 = () => {
  dispatch(action 객체)
}

import { createStore } from 'redux';

const initialState = { counter: 0, showCounter: true };

const counterReducer = (state = initialState, action) => {
  if (action.type === 'increment') {
    return {
      counter: state.counter + action.amount,
      showCounter: state.showCounter,
    };
  }

  if (action.type === 'decrement') {
    return {
      counter: state.counter - 1,
      showCounter: state.showCounter,
    };
  }

  if (action.type === 'toggle') {
    return {
      counter: state.counter,
      showCounter: !state.showCounter,
    };
  }

  return state;
};

const store = createStore(counterReducer);

export default store;

 

import classes from './Counter.module.css';
import { useDispatch, useSelector } from 'react-redux';

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

  const incrementHandler = (amount) => {
    dispatch({ type: 'increment', amount: amount });
  };

  const decrementHandler = () => {
    dispatch({ type: 'decrement' });
  };

  const toggleCounterHandler = () => {
    dispatch({ type: 'toggle' });
  };

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      {showCounter && <div className={classes.value}>{counter}</div>}
      <div>
        <button onClick={() => incrementHandler(1)}>Increment</button>
        <button onClick={() => incrementHandler(5)}>Increment 5</button>
        <button onClick={decrementHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;

 

import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';

import './index.css';
import App from './App';
import store from './store';

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