Redux - 상태 관리 라이브러리

goodjam92·2023년 4월 11일
0

redux

목록 보기
1/3
post-thumbnail

서론

이전 회사에서 상태 관리 라이브러리로Recoil을 사용했었습니다. 깊게 사용하기보단 주로 전역 변수의 상태 관리를 위해 사용하였었는데 그 때 Redux가 아닌 Recoil을 사용했던 이유는 좀 더 사용방법이 간단하고, 단기간에 학습하여 적용하기가 쉽다는 점 때문이었죠. 그렇게 Recoil을 사용하였지만, Redux에 대한 궁금증이 계속 있었기에 한 번 학습해보면서 내용을 정리해보기로 하였습니다.

상태 관리 라이브러리를 사용하는 이유?

React에서 우리가 컴포넌트들을 작성하다보면 부모-자식 간에 props를 주고 받을 때가 있습니다. 이 props는 프로젝트가 커질수록 컴포넌트의 계단이 많아지고, 컴포넌트 간의 props를 전달하는 동작이 늘어나게 됩니다. props가 수많은 계단을 거치면서 불필요한 리렌더링을 일으키고, 코드의 가독성을 떨어뜨려 유지보수에 어려움이 발생할 수 있습니다.

  • Props Drilling

이러한 문제를 상태 관리 라이브러리가 상태(state)를 전역으로 관리하여 계단을 거치지 않고 필요한 컴포넌트에서 바로 호출할 수 있도록 해줍니다.

Redux 란?

리덕스란 자바스크립트 앱의 상태 관리 라이브러리입니다. 리덕스는 Javascript, React 또는 Angular와 같은 프레임워크에서도 사용할 수 있다보니 현재 상태 관리 라이브러리중에 가장 인기가 많습니다. 리덕스를 사용하면 컴포넌트들의 상태 관련 로직들을 다른 파일들로 분리시켜 더욱 효율적으로 관리할 수 있습니다.

Redux에서 사용되는 키워드

액션(action)과 액션 생성함수(action creator)

우리가 상태에 어떤 변화를 주어야 할 때 액션을 발생시킵니다. 액션은 객체로 표현되며 다음과 같은 형식으로 되어있습니다.

{
  type: "Add_ToDo"
  내용: {
    할일: "리덕스 배운거 정리하기"
    일시: new Date()
  }
}

type은 필수적으로 갖고 있어야하며, 그 외에는 저장할 정보를 넣어줍니다. 이러한 액션을 나중에 컴포넌트에서 쉽게 액션을 발생시키기 위해 따로 액션 생성함수를 만들어서 사용합니다. 반드시 액션 생성함수를 사용해야하는 것은 아닙니다.

export const addToDo = text => {
  return {
    type: "ADD_ToDo",
    할일: text
  };
};

export function deleteToDo (id) => {
  return {
    type: "DELETE_ToDo",
    id
  };
};

리듀서 (Reducer)

리듀서는 변화를 일으키는 함수입니다. 리듀서는 두 가지의 파라미터를 받아오는데 다음과 같은 형태입니다.

function reducer(state, action) {
  if (action.type === "ADD_ToDo") {
    return (... addState(action.할일));
  } else if (action.type === "DELETE_ToDo") {
      return (... deleteState(action.id));
    }
  return state 
}

이해하기 조금 쉽게 if, else를 사용하여 작성해보았습니다만 받아오는 type에 따라 다른 행동을 해야한다는 조건에 알맞는 문법이 있습니다. 바로 switch를 사용하면 코드가 좀 더 보기 좋아질겁니다.

function reducer(state = [], action) {
  switch (action.type) {
    case "ADD_ToDo":
      return (... addState(action.할일));
    case "DELETE_ToDo":
      return (... deleteState(action.id));
    default:
      return state;
  }

훨씬 보기 편하지 않나요? 보통 Redux에선 이렇게 리듀서를 구성합니다. 보통 리덕스에서는 여러개의 리듀서(Sub Reducer)를 만들고 이를 합쳐서 루트 리듀서(Root Reducer)를 만들 수 있습니다.

스토어 (Store)

리덕스에서는 한 앱당 하나의 스토어를 만듭니다. 스토어에는 현재 앱 상태와 리듀서가 들어가고, 몇 가지 내장 함수를 포함하고 있습니다.

import createStore from "redux";
const store = createStore(reducer);

createStore를 import하면 줄이 그어져서 createStore 이렇게 나올겁니다. 그냥 사용해도 문제가 없지만 보기 싫으시다면 이렇게 코드를 작성하면 됩니다.

import { legacy_createStore as createStore } from "redux";

createStore를 사용할 순 있지만 학습 목적 외에는 @reduxjs/toolkitconfigureStore를 사용하는 것을 권장한다고 하네요. 이 부분은 뒤에 toolkit내용에서 다뤄보도록 하겠습니다.

디스패치 (dispatch)

디스패치는 스토어의 내장함수입니다. 액션을 발생시키는 함수라고 생각하시면 되는데 dispatch(action) 파라미터로 액션을 전달합니다. 호출하게 되면 스토어는 리듀서 함수를 실행시켜 해당 액션의 로직을 참고하여 새로운 상태를 만들게됩니다.

store.dispatch(addTodo("오늘은 쉬자!"));

//or

import { useDispatch } from "react-redux"
const dispatch = useDispatch();
dispatch(addTodo("오늘은 쉬자!"));

구독 (subscribe)

스토어의 내장함수이며 구독은 함수 형태의 값을 파라미터로 받습니다. 구독 함수에 특정 함수를 전달해주면 액션이 디스패치 되었을 때마다 전달해준 함수가 호출됩니다.

const showState = () => {
  // 현재 스토어의 상태를 가져오는 method
  const state = store.getState();
  console.log(state);
};

// 액션이 dispatch 될 때마다 showState 함수 실행
store.subscribe(showState);

리액트 환경에서는 많이 사용되지는 않고, react-redux 라이브러리에서 제공되는 connect, useSelector로 스토어 상태를 구독합니다.

리덕스의 3가지 규칙

하나의 어플리케이션에는 하나의 스토어만!

  • 여러개의 스토어를 사용하는 것은 가능하지만 권장되지 않습니다.
  • 리덕스 개발 도구를 활용하지 못합니다.

상태는 읽기 전용이다

  • 리액트처럼 state를 직접 수정하지 않고, setState를 사용하는 것처럼 state를 업데이트 해야합니다.
    • 배열의 경우 state.push와 같은 mutate 함수 사용 금지
    • 새로운 배열을 만들어서 교체하는 방식으로 업데이트를 해야 함
  • 리덕스에서 불변성을 유지해야 하는 이유
    • 내부적으로 데이터가 변경되는 것을 감지하기 위한 shallow equality 검사를 하기 때문이다.
    • 객체의 변화를 감지 할 때 객체의 안쪽까지 하지 않고, 겉에만 비교하여 좋은 성능을 유지한다.

리듀서는 순수 함수여야 한다

  • 리듀서 함수는 이전 상태와, 액션 객체를 파라미터로 받는다.
  • 이전 상태는 절대로 건드리지 않고, 변화를 일으킨 새로운 상태 객체를 만들어 반환한다.
  • 같은 파라미터로 호출된 리듀서는 언제나 똑같은 결과 값을 반환해야 한다.

정리

지금까지는 리덕스의 가장 기본적인 이론을 중점으로 글을 정리하였습니다. 리덕스의 핵심 키워드와 키워드의 가장 기본적인 코드의 형태, 그리고 우리가 리덕스를 사용하면서 반드시 지켜야 할 것들을 알 수 있었는데요. 다음 글에서는 제가 학습했던 강의를 토대로 코드 위주로 사용법을 한 번 알아보고자 합니다. 그럼 다음 글에서 뵙겠습니다 감사합니다!

.
.
.
.
.

참고사이트
[벨로퍼트와 함께하는 모던 리액트] - 리덕스

profile
습관을 들이도록 노력하자!

0개의 댓글