[Trouble-Shooting] Redux로 state 관리하기

Joosi_Cool·2023년 1월 9일
2

Frond-End

목록 보기
4/8
post-thumbnail

들어가기 전

저번 블로깅에선 Redux에 대한 개념에 집중적으로 다루어보았다.
이번 블로깅에선 실제로 프로젝트에 적용해보는 경험을 하려고 한다.
만약 Redux에 대한 개념이 궁금하다면, 아래 링크를 참고해보자.

[Front-End] Redux란? https://velog.io/@sean2337/Front-End-Redex%EB%9E%80


Problem recognition(문제인식)

본인이 Redux에 대해 공부한 이유는 사이드 프로젝트 진행중에, 문제를 인식했기 때문이다. 프로젝트에서 필요로 되어지는게, 하나의 State 를 여러 컴포넌트에서 필요로 되어졌다. 평소에 쓰던 방법은 props 란 방법을 사용했다. 하지만 이번만큼은 이를 가지고 하기엔 힘들었다.

컴포넌트 마다의 부모자식 관계가 매우 많았고, 이에 대해 props를 넘겨주기란 쉽지 않을 일이고, 비효율적인 코딩이였다.

또한 더 문제가 되었던 단계가 Back-End 의 API를 합치는 과정이였다. API를 사용해서 어떤 State를 계속 업데이트 해주고, 값을 사용자들에게 보여줘야 한다. 이러한 API들이 사용되는 모든 컴포넌트에서 Back-END API를 사용하기엔 너무 비효율적이였다.

그래서 본인이 선택한 방법이 Redux 였다. 여러가지 공부를 해보니, Redux 를 활용하면, props 를 줄 필요 없이, 어떤 컴포넌트에서든 불러낼 수 있었다.
뿐만 아니라, 한곳에서 state를 관리하기 때문에 Back-EndAPI 를 한곳에서만 불러서 이를 필요한 컴포넌트마다 state 값만 뿌려줄 수 있었다. 비효율적인 작업을 없앨 수 있었다.
앞서 문제인식 단계에서 느낀 문제를 해결할 수 있었다. 그래서 이를 공부했고, 활용하고자 한다.

Trouble-Shooting

자 이제, 한번 Redux를 적용시켜보자.

시작하기 전, 설치

우선 한 일은 React에서 Redux를 설치해주었다.

npm i @reduxjs/toolkit react-redux redux-flipper

두번째는 React에서 제일 부모의 index.jsx 가 있다. 여기에서 우리가 사용해줄 statestore, reducer 등등을 설정해주어야 한다. 하나씩 가보자.

최상위 파일(index.jsx)

  1. 사용해줄 state 생성
var BPM = 100;

-> 본인 프로젝트에선 기본값이 100인 BPM이라는 state가 필요했고, 이렇게 설정해주었다.


  1. store 생성
import { createStore } from "redux";
{생략...}
let store = createStore(reducer);

-> store 만들어주기 위해 createStore 를 import를 해주고, store를 생성해준다.
단, 여기서 reducer 함수가 꼭 들어가야한다. 이래야 값에 접근할 수 있다.


  1. reducer 함수 생성
function reducer(state = BPM, action) {
  if (action.type === "1증가") {
    state++;
    return state;
  } else if (action.type === "1감소") {
    state--;
    return state;
  } else if (action.type === "scroll") {
    state = action.changeNum;
    return state;
  } else {
    return state;
  }
}

-> 여기서는 뒤에 좀더 설명하겠지만, 우리가 state값을 변경하고 싶을때 쓰는 함수이다. 여기서만 state를 변경할 수 있다. 변수는 이전 값(이전 state)와 action 값이다. action 값이 이후에 우리가 던져줄 값이다.

예시코드
if (action.type === "1증가") {
state++;
return state;
}

이말은 action.type를 "1증가"로 던져주면 이전 state에 +1을 해서 state를 변경시켜주라는 말이다.


4. Provider로 묶어주기
import { Provider } from "react-redux";

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

-> 이는 React에서 앱 실행시, 최상위 index.jsx에서 보여줄 영역을 Provider로 묶어 주어야 한다. 이는 Redux 사용 규격이니 알아두자.

총 최상위 index.jsx 파일 코드

import React from "react";
import ReactDOM from "react-dom/client";
import Router from "./routes";
import { createGlobalStyle } from "styled-components";
import reset from "styled-reset";
import { Provider } from "react-redux";
import { createStore } from "redux";

var BPM = 100;


function reducer(state = BPM, action) {
  if (action.type === "1증가") {
    state++;
    return state;
  } else if (action.type === "1감소") {
    state--;
    return state;
  } else if (action.type === "scroll") {
    state = action.changeNum;
    return state;
  } else {
    return state;
  }
}

let store = createStore(reducer);

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

자 이제 최상위 index.jsx에서 만들껀 다 해놨다. 이제 쓰고 싶은 컴포넌트에 가서 불러오자.



Component에서 불러오기

  1. state 값 불러오는 방법
    이는 매우 간단하다. 아래 코드 같이 하면된다.
import { useSelector } from "react-redux";

{...생략}

const BPM = useSelector((state) => state); // BPM이라는 변수에 state 불러오기 

  1. Dispatch 설정
import { useDispatch} from "react-redux";

{...생략}

const dispatch = useDispatch();

우선 위와 같이 dispatch를 사용할 수 있게 초기 설정을 해준다.

  1. Dispatch으로 action주기

만약 버튼을 클릭시에 dispatch를 발동시키고 싶다면 어떻게 해야할까?

	<AiOutlineMinus
        onClick={() => {
           dispatch({ type: "1감소" });
         }}
         size="35"
   />

간단하다. dispatch안에 action값을 넣어주면 가능하다.

Redux에 대해 공부하기 전에 본인이 만든 코드는 아래와 같아.

const [BPM, setBPM] = React.useState(100);

  //Plus 버튼 누를시 counter 1증가
  function PlusClick() {
      setBPM(BPM + 1);
  }

useState를 이용해서, BPM state를 만들어주고 setBPM을 이용하여 state값에 변화를 주었다.
사실 코드를 보면 알 수 있듯이 두개 다 맞는 표현이다. 하지만 component 가 엄청 많아지고, 거기에 따라 부모 자식 관계가 어머어마하게 많아진다면, 이는 Redux라는 기술을 도입하는 것이 맞을 것이다.

아래의 코드는 Redux를 이용한 나의 코드이다. 다른 부분은 너무 부가적인 내용이고, Redux만 들어간 부분을 담았다.

	// +버튼 
     <AiOutlinePlus
          onClick={() => {
            dispatch({ type: "1증가" });
          }}
          size="35"
    />
	// - 버튼
	<AiOutlineMinus
        onClick={() => {
           dispatch({ type: "1감소" });
         }}
         size="35"
   />
	//scroll바 
	<input
       type="range"
       min={0}
       max={200}
       step={5}
       value={BPM}
       onChange={(event) => {
         //setBPM(event.target.valueAsNumber);
         dispatch({ type: "scroll", changeNum: event.target.valueAsNumber 			});
       }}
     />

이를 통해 아래와 같이 기능 구현이 되었다.

정리

이번에는 component의 공통된 state를 해결하기 위해 기존에 사용하던 props 대신하여 Redux 라는 새로운 기술로 Trouble-Shooting 을 하였다.
처음에는 Redux 를 state를 다른 component에서 props 없이 사용하고자 했지만, Redux에 대해 배울수록 이 말고도 더 큰 장점들이 눈에 많이 들어왔다.
예를 들어, Redux 는 state를 reducer라는 것으로 값을 바꾼다. 여기서 중요한건 다른거로는 절대 state를 바꾸지 못한다는 것이다.
이점에 왜 중요하다고 느꼈을까? 개발 공부를 많이 하다보면, 개발자들이 변수 선언 할때도 const 나 let 같이 var과 다르게 이런걸 쓰면서 최대한 제한을 두려고 한다. 왜 그럴까?
물론 해킹의 위험성을 줄이려고 하는것도 맞다. 또한 개발을 할때, error 들이 매우 많이 발생한다. 이때 제한을 두지 않는다면, 어디서 error가 발생했는지 알지 못한다. 이는 개발 시에 매우 치명적이다.

reducer 로만 state값을 변화시킬 수 있다고 했다. 이제 내가 말하려는 것을 눈치 챘을 것이다.
state 값에 의도치 않은 값 (error) 가 있다면 모든 코드를 다 봐야할까?

그렇지 않다. reducer 쪽만 보면 된다. 이것이 state관리를 매우 쉽게 한다.

이번에 프로젝트를 진행하면서, state값에서 자주 error 가 발생했다. 하지만 이 Redux를 도입함으로써 props문제 뿐 아니라 state 관리 측면에서도 매우 효율적으로 할 수 있게 되었다.

항상 state를 쓸때, Redux를 쓰는게 답은 아닐 것이라고 생각한다. 이것은 라이브러리 이기 때문에 무게가 꽤 있을 것이라고 생각한다. props 같은 것으로 해결이 가능한 간단한 state 라면 props를 사용하는 것이 효율적일 수 있다.

이번 Trouble Shooting으로 항상 state 쓸때, Redux를 써야지!! 이게 아니라, Redux라는 선택지를 하나 더 얻었다고 생각하려고 한다. 다음 웹 서비스를 만들때, 이러한 선택지를 최대한 이용할 수 있을 것이라고 생각이든다.

profile
집돌이 FE개발자의 노트

1개의 댓글

comment-user-thumbnail
2023년 1월 11일

좋은 글 감사합니다 🥸

답글 달기