[리덕스] 기본 파일 구조 및 형태 익히기

AnSuebin·2022년 12월 5일
0

리덕스를 쓰는 방법은 다양하다. 그래서 더더욱 나에게 좋은 파일 형태를 찾아 먼저 익숙해 지는 것이 리덕스를 이해하는데 도움이 될 것이라 생각했다.
따라서 간단해 보이는 리덕스 파일구조를 정리하고, 이를 우선적으로 몸에 익히려 한다.

01. 파일 구조

  • redux라는 폴더를 만들어 그 안에서 스토어 및 모듈을 관리한다.
  • Store은 config에 기능들은 modules에 넣어 저장한다.

02. configStore

  • config에 들어가야 할 내용
    • configStore는 말 그대로 Store에서 필요한 내용을 정리한 파일이다.
    • 따라서 store를 만드는 createStore을 가져오고
    • 리듀서들을 가져와서 묶어주고 이를 Store로 저장해줘야한다.
    • 다시한번 순서를 정리해보자면
      1. modules들을 가져와
      2. combineReducers를 통해 리듀서들을 묶어
      3. 하나의 Reducer로 만들어준다.
      4. 이를 createStore로 Store를 만들어준다.
      5. store를 내보내 준다.
import { createStore } from "redux";
import { combineReducers } from "redux";
import counter from "../modules/counter";

const rootReducer = combineReducers({
  counter: counter,
});
const store = createStore(rootReducer);

export default store;

03. index.js

  • index에 들어가야 할 내용
    • store를 가져와 전역적으로 사용할 수 있어야한다.
    • 따라서 Index.js에서 해야할 일은 store에서 가져와, 컴포넌트에 provider로 뿌려줘야한다.
// 원래부터 있던 코드
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

// 우리가 추가할 코드
import store from "./redux/config/configStore";
import { Provider } from "react-redux";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  //App을 Provider로 감싸주고, configStore에서 export default 한 store를 넣어줍니다.
  <Provider store={store}>
    <App />
  </Provider>
);

04. modules

  • modules에 들어가야 할 내용
    • modules 내부에 들어갈 파일 또한 다양하게 구성될 수 있는데
    • 기본적으로 기능 혹은 페이지별로 state를 관리한다고 한다.
    • 들어가야 할 내용은 크게 4가지이고
    • import할 것은 따로 없다.
  1. Action Value : 액션 타입 정의하기

    • 액션 타입을 정의해줘야 나중에 어떤 액션이 있는지 한눈에 볼 수 있다.
    • 또한 액션에 관한 오타를 줄일 수 있다.
    • 액션 명이 중복되면 충돌 문제가 발생하기 때문에 모듈 이름/ 액션 이름으로 작성하면 좋다.
const ADD_NUMBER = "counter/ADD_NUMBER";
const MiNUS_NUMBER = "counter/MINUS_NUMBER";
  1. Action Creator : 액션 생성 함수 만들기

    • 이 함수를 다른 파일에서 불러와 사용하도록 하는 것에 목적이 있다.
    • type과 받아올 props를 지정해준다.
    • type은 앞에서 정의한 대문자 명을 사용하고,
    • 받아올 props는 payload라는 명칭을 사용한다.
// Action Creator
export const addNumber = (payload) => {
  return {
    type: ADD_NUMBER,
    //키와 value가 같으면 하나로 줄여 작성 가능 ES6
    payload,
  };
};

export const minusNumber = (payload) => {
  return {
    type: MiNUS_NUMBER,
    payload,
  };
};
  1. Initial State : 초기 상태값 설정
    • 이 부분은 생략하는 경우도 있다.
    • useState의 초기값을 ()내부에 적어줬던 것과 마찬가지로 설정해주고 내려오면 깔끔하다
    • 이를 나중에는 default값으로 설정한다.
// Initial State
const initialSate = {
  number: 0,
};
  1. Reducer : 리듀서 함수 만들기( 가장 중요!)
    • 리듀서 함수 이름을 따라 파일명으로 만든다.
    • 조건에 맞게 return에 state값을 받아 새로운 형태로 변경해 준다.
    • 기본적으로 initialState가 객체이기 때문에 처음에 구조분해 할당을 통해 복사 후, 덮어씌우는 구조로 정리하는 것이 좋다.
    • 리턴 값은 말그대로 값
// state 값이 하나인 경우

// Initial State
const initialSate = {
  number: 0,
};

// Reducer
const counter = (state = initialSate, action) => {
  switch (action.type) {
    case ADD_NUMBER: {
      return {
        number: state.number + action.payload,
      };
    }
    case MiNUS_NUMBER: {
      return {
        number: state.number - action.payload,
      };
    }
    default:
      return state;
  }
};
// state 값이 여럿인 경우

// Initial State
const initialSate = {
  input: '',
  todos: [{id: 1, text: '리덕스 기초 배우기', done: true}, 
  {id: 2, text: '리덕스와 리덕스 사용하기', done: false}]
};

// Reducer
const counter = (state = initialSate, action) => {
  switch (action.type) {
    case CHANGE_INPUT: {
      return {
        ...state,
        input: action.input
      };
    }
    case INSERT: {
      return {
        ...state,
        todos: state.todos.concat(action.todo)
      };
    }
    case TOGGLE: {
      return {
        ...state,
        todos: state.todos.map(todo =>
        todo.id === todo.id?{...todo, done:!todo.done}:todo
      };
    }
    default:
      return state;
  }
};

05. Components : 리덕스 사용하기

  • 리덕스를 사용하는 Component에 들어가야 할 내용
    • Hooks를 사용해 가져온다.
    • 총 두가지의 훅을 사용
      • useSelector : state 값 가져오는 훅
      • useDispatch : action을 가져오는 훅
    • useSelectior
      • useSelector를 react-redux에서 Import
        import { useSelector} from "react-redux";
      • component 함수 내에서 전역 state 값 가져오기
        const globalNumber = useSelector((state) => state.counter.number);
      • component 함수 return에서 사용하기
        <div>{globalNumber}<div>
    • useDispatch
      • useDispatch를 react-redux에서 Import
        import { useDispatch} from "react-redux";
      • dispatch할 액션들 가져오기
        import { addNumber, minusNumber } from "./redux/modules/counter";
      • dispatch 선언
        const dispatch = useDispatch();
      • Handler에 dispatch로 선언해주기 / return에 넣어주기
  const onClickAddNumberHandler = () => {
    dispatch(addNumber(number));
  };
  const onClickMinusNumberHandler = () => {
    dispatch(minusNumber(number));
  };
    • 전체
  return (
    <div>
      {globalNumber}
      <input type="number" onChange={onChangeHandler} value={number} />
      <button onClick={onClickAddNumberHandler}>더하기</button>
      <button onClick={onClickMinusNumberHandler}>빼기</button>
    </div>
  );
// src/App.js

import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addNumber, minusNumber } from "./redux/modules/counter";

const App = () => {
  const [number, setNumber] = useState(0);
  const globalNumber = useSelector((state) => state.counter.number);
  const dispatch = useDispatch();
  const onChangeHandler = (e) => {
    const { value } = e.target;
    setNumber(+value);
  };
  const onClickAddNumberHandler = () => {
    dispatch(addNumber(number));
  };
  const onClickMinusNumberHandler = () => {
    dispatch(minusNumber(number));
  };

  return (
    <div>
      {globalNumber}
      <input type="number" onChange={onChangeHandler} value={number} />
      <button onClick={onClickAddNumberHandler}>더하기</button>
      <button onClick={onClickMinusNumberHandler}>빼기</button>
    </div>
  );
};

export default App;
profile
고객에게 명료한 의미를 전달하고, 명료한 코드를 통해 생산성 향상에 기여하고자 노력합니다.

0개의 댓글