Redux - React Redux

ryan·2022년 6월 22일
0

React에 Redux 적용하기

폴더 구조

  • store folder

    • 저장소가 관리되는 폴더
  • reducers

    • 앱에서 사용할 reducer들을 관리하는 폴더(index에서 합쳐서 export한다)

1. Store 생성

  • 기존 방식은 createStore(import from 'redux')를 통해 store를 생성했지만, redux에서 새롭게 권장하는 방식인 configureStore를 사용하여 store를 생성했다.
  • 기존 방식과의 차이점은 참고 블로그에서 확인할 수 있다.
store - index.js

import {configureStore} from '@reduxjs/toolkit';
import reducers from '../reducers/';

const store = configureStore({
  reducer: reducers,
});
console.log(store);
export default store;

2. Provider 추가

  • 컴포넌트 트리에서 가장 상위레벨에서 Provider(제공자)를 설정해야 모든 컴포넌트에서 store에 접근이 가능하다.
index.js

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

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

ReactDOM.render(
  // 최상위 컴포넌트에 Provider를 설정하고 생성한 store를 연결한다.
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

3. Reducer 작성

  • 본 포스팅에서는 reducer를 분리하고 합치는 걸 연습해보기 위해서 여러 파일로 나눴고, 하나의 reducer에서 관리해도 된다.
  • reducer는 기본적으로 useReducer와 작성 방법이 동일하다.

counter.js

: counter state를 증가/감소 시키는 reducer

const initialState = {counter: 0};

const counter = (state = initialState, action) => {
    // 절대 기존의 state를 변경해서는 안 됨.
    // 예측 불가능한 동작이 발생하거나, 디버깅이 어려움,
    // state가 동기화되지 않는 더 큰 앱에서 부작용이 발생할 수 있음. 
    // UI가 state를 정확히 반영하지 않을 수 있음.
  switch (action.type) {
    case 'INCREMENT':
      return {...state, counter: state.counter + 1};

    case 'DECREMENT':
      return {...state, counter: state.counter - 1};

    case 'INCREASE':
      return {...state, counter: state.counter + action.amount};

	default:
      return {...state};
  }
};
export default counter;

showContent.js

: 컴포넌트 동적으로 보여주기 위한 boolean state

const showContent = (state = {show: true}, action) => {
  switch (action.type) {
    case 'SHOW':
      return {...state, show: true};

    case 'HIDE':
      return {...state, show: false};

    default:
      return {...state};
  }
};

export default showContent;

Reducer 병합

  • 합쳐진 rootReducer는 위의 1.Store 생성에서 reducers라는 이름의 객체로 받았다.

    index.js

    : counter.js와 showContent.js를 합친다.

    // combineReducers를 통해 분리한 reducer를 합칠 수 있고, 
    // reducer의 이름을 따로 설정할 수도 있다.
    import {combineReducers} from 'redux';
    import counter from './counter';
    import showContent from './showContent';
    
    const rootReducer = combineReducers({
      counter, // count : counter
      showContent, // show : showContent
    });
    
    export default rootReducer;

컴포넌트에서 Action 발생시키기

  • react-redux의 커스텀 훅인 useSelector, useDispatch를 import 한다.
  • useSelector또는 useStore를 통해 저장소에 있는 reducer와 연결할 수 있지만,
    useSelector는 자동으로 스토어가 관리하는 상태의 일부를 선택하게 해준다.
Counter.js

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

const Counter = () => {
  const dispatch = useDispatch(); // dispatch 호출
  
  // 관리하고 싶은 state의 일부를 return함
  // useSelector를 이용하여 리덕스가 자동으로 subscription을 설정해줌.
  const {counter} = useSelector((state) => state.counter);
  const {show} = useSelector((state) => state.showContent);
  // counter,showContent는 reducers라는 객체로 store에서 관리되기 때문에,
  // 구조분해할당을 통해 state 값을 상수로 선언한다.
  
  
 
  const incremnetHandler = () => {
    dispatch({type: 'INCREMENT'});
  };
  const increaseHandler = () => {
    dispatch({type: 'INCREASE', amount: 5});
  };
  const decremnetHandler = () => {
    dispatch({type: 'DECREMENT'});
  };
  const toggleCounterHandler = () => {
    show ? dispatch({type: 'HIDE'}) : dispatch({type: 'SHOW'});
  };
    // click event가 발생했을 때, 
    // dispatch를 통해 발생한 action을 reducer에 전달해주면
    // reducer는 type을 읽고 설정했던 action type에 맞는 리턴값이 전달된다. 
  ![](https://velog.velcdn.com/images/simplicityyy/post/1ab41e70-430a-4e5c-bac9-61df0c578c7c/image.gif)

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      {show && <div className={classes.value}>{counter}</div>}
      <div>
        <button onClick={incremnetHandler}>Increment</button>
        <button onClick={increaseHandler}>Increment BY 5</button>
        <button onClick={decremnetHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;

profile
프론트엔드 개발자

0개의 댓글