[React] Redux 사용하기

homile·2022년 8월 30일
2

React

목록 보기
1/3

Redux?

상태를 전역적으로 관리하기 위해서 사용되는 상태관리 도구이며, Redux 외에도 MobX, React Context, Recoil 등이 있습니다.
상태관리 도구를 사용하여 Props drilling 이슈를 해결할 수 있습니다.

Props drilling?
상태가 존재하는 컴포넌트에서 자식 컴포넌트로 이동을 할 때, 수많은 props를 계속해서 내려야하는 경우를 말하며, 코드의 가독성이 나빠지고 유지보수 또한 힘들어집니다.

Action

상태에 어떤 Action(행동)을 취할 것인지 정해놓는 객체입니다.
Action이 많아질 경우 ActionTypes 파일을 생성하여 타입을 모아두는 경우도 있습니다.
Action 타입을 정의할 때는 모두 대문자로 Snake Case로 작성합니다.

// 전달 받을 값(payload)가 없을 경우
export const loginSuccess = () => ({
  type: "LOGIN_SUCCESS"
})

// 전달 받을 값(payload)가 있을 경우
// payload는 주로 단일 데이터, 객체로 받습니다.
export const loginInfo = (res) => ({
  type: "LOGIN_INFO",
  payload: res
})

Reducer

Dispatch에서 전달받은 Action(행동) 객체의 type에 따라서 상태를 변경시키는 함수입니다. Reducer가 여러개 일 경우 combineReducers를 사용하여 하나로 묶어줄 수 있습니다.

Store

상태가 관리되는 오직 하나뿐인 상태 저장소의 역할을 합니다.
createStore을 사용할 경우 toolkit을 사용하라는 의미로 밑줄이 그어집니다.

import { createStore } from "redux";
import rootReducer from "./redux/reducers";

// Reducer를 연결한다.
const store = createStore(rootReducer);

export default store;

React-redux 초기 세팅

redux 라이브러리 설치

React에서 Redux를 사용하기 위해서는 redux, react-redux를 모두 설치해야 합니다.
아래의 코드에서 @reduxjs/toolkit은 후에 react-toolkit을 사용하기 위해 설치한 것입니다.

npm install @reduxjs/toolkit redux react-redux

파일 구조 생성

redux-test
└─ src
   ├─ App.js     메인화면
   ├─ Compo1.js  프롭받을 컴포넌트
   ├─ Compo2.js  프롭받을 컴포넌트
   ├─ index.css
   ├─ index.js
   ├─ redux
   │  ├─ actions  액션 정의
   │  │  └─ login.js
   │  └─ reducers 상태 변경 함수
   │     ├─ index.js
   │     └─ loginReducer.js
   └─ store.js    상태 저장소

Actions 폴더 생성

  • 액션에 관한 파일 생성
  • 액션 타입과 액션을 각각의 파일로 생성해도 무관하다.
// login.js
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_INFO =  "LOGIN_INFO";

export const loginSuccess = () => ({
  type: LOGIN_SUCCESS
})

export const loginInfo = (res) => ({
  type: LOGIN_INFO,
  payload: res
})

Reducers 폴더 생성

  • 리듀서를 정의할 파일 생성
// index.js
import { combineReducers } from "redux";
import loginReducer from "./loginReducer";

// 여러 리듀서들을 하나로 묶어준다.
const rootReducer = combineReducers({
  loginReducer,
});

export default rootReducer;

// loginReducer.js
import { LOGIN_SUCCESS, LOGIN_INFO } from "../actions/login";

// 초기 상태 지정
const initialstate = {
  isLogin: false,
  userName: "",
};

// 초기 상태 불변성
const loginReducer = (state = initialstate, action) => {
  switch (action.type) {
    case LOGIN_SUCCESS:
      return {
        // 순서 중요
        ...state,
        isLogin: true,
      };
    case LOGIN_INFO:
      return {
        isLogin: true,
        userName: action.payload,
      };
    default:
      return state;
  }
};

export default loginReducer

루트 폴더 src폴더에 store.js 파일 생성

  • store.js: 상태가 저장되는 저장소
// store.js
// 취소선: redux toolkit 사용하란 의미
import { createStore } from "redux";
import rootReducer from "./redux/reducers";

const store = createStore(rootReducer);

export default store;

Redux 상태 사용하기

Redux의 상태를 변경 및 불러오기 위해서는 useDispatch, useSelector가 필요합니다.

useDispatch

Reducer를 호출하여 Action을 전달해주는 함수이다. 전달인자로는 Action의 객체가 전달된다.
useDispatch를 사용하기 위해서는 변수에 할당해 준뒤 사용할 수 있다.

import { useDispatch } from "react-redux";
import { loginInfo, loginSuccess } from "./redux/actions/login";

// 사용하기위해 변수에 할당(함수형식)
const dispatch = useDispatch();

// 전달인자가 없을 경우
dispatch(loginSuccess());

// 전달인자가 있을 경우
dispatch(loginInfo("homil2"));

useSelector

컴포넌트와 state를 연결하여 Redux의 state에 접근할 수 있게 해주는 메서드이다.
함수내에서는 사용할 수 없다.

import { useSelector } from "react-redux";

// 위에서 정의한 loginReducer의 상태 값을 객체로 받아온다.
useSelector((state) => state.loginReducer)

실사용

로그인 버튼 클릭시 로그인상태가 유지되며 유저네임을 작성후 전송하면 해당 유저의 이름이 같이 담기도록 하는 코드를 구현했다.

// app.js
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { loginInfo, loginSuccess } from "./redux/actions/login";

const App = () => {
  const dispatch = useDispatch();
  const [name, setName] = useState("");

  const nameChange = (el) => {
    setName(el)
  };
  console.log(useSelector((state) => state.loginReducer))

  const loginBtnClick = () => {
    dispatch(loginSuccess())
    dispatch(loginInfo(name))
  };

  return (
    <div className="container">
      <div>
        <label htmlFor="name">이름</label>
        <input id="name" onChange={(el) => nameChange(el.target.value)}></input>
      </div>
      <div>
        <button type="button" onClick={loginBtnClick}>
          로그인
        </button>
      </div>
    </div>
  );
};

export default App;

// index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";

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

profile
Frontend Developer

0개의 댓글