저번 블로깅에선 Redux에 대한 개념에 집중적으로 다루어보았다.
이번 블로깅에선 실제로 프로젝트에 적용해보는 경험을 하려고 한다.
만약 Redux에 대한 개념이 궁금하다면, 아래 링크를 참고해보자.
[Front-End] Redux란? https://velog.io/@sean2337/Front-End-Redex%EB%9E%80
본인이 Redux에 대해 공부한 이유는 사이드 프로젝트 진행중에, 문제를 인식했기 때문이다. 프로젝트에서 필요로 되어지는게, 하나의 State
를 여러 컴포넌트에서 필요로 되어졌다. 평소에 쓰던 방법은 props
란 방법을 사용했다. 하지만 이번만큼은 이를 가지고 하기엔 힘들었다.
컴포넌트 마다의 부모자식 관계가 매우 많았고, 이에 대해 props를 넘겨주기란 쉽지 않을 일이고, 비효율적인 코딩이였다.
또한 더 문제가 되었던 단계가 Back-End
의 API를 합치는 과정이였다. API를 사용해서 어떤 State를 계속 업데이트 해주고, 값을 사용자들에게 보여줘야 한다. 이러한 API들이 사용되는 모든 컴포넌트에서 Back-END
API를 사용하기엔 너무 비효율적이였다.
그래서 본인이 선택한 방법이 Redux
였다. 여러가지 공부를 해보니, Redux
를 활용하면, props
를 줄 필요 없이, 어떤 컴포넌트에서든 불러낼 수 있었다.
뿐만 아니라, 한곳에서 state를 관리하기 때문에 Back-End
의 API
를 한곳에서만 불러서 이를 필요한 컴포넌트마다 state 값만 뿌려줄 수 있었다. 비효율적인 작업을 없앨 수 있었다.
앞서 문제인식 단계
에서 느낀 문제를 해결할 수 있었다. 그래서 이를 공부했고, 활용하고자 한다.
자 이제, 한번 Redux를 적용시켜보자.
우선 한 일은 React
에서 Redux
를 설치해주었다.
npm i @reduxjs/toolkit react-redux redux-flipper
두번째는 React에서 제일 부모의 index.jsx
가 있다. 여기에서 우리가 사용해줄 state
와 store
, reducer
등등을 설정해주어야 한다. 하나씩 가보자.
var BPM = 100;
-> 본인 프로젝트에선 기본값이 100인 BPM
이라는 state
가 필요했고, 이렇게 설정해주었다.
import { createStore } from "redux";
{생략...}
let store = createStore(reducer);
-> store
만들어주기 위해 createStore
를 import를 해주고, store를 생성해준다.
단, 여기서 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를 변경시켜주라는 말이다.
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 사용 규격
이니 알아두자.
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에서 만들껀 다 해놨다. 이제 쓰고 싶은 컴포넌트에 가서 불러오자.
import { useSelector } from "react-redux";
{...생략}
const BPM = useSelector((state) => state); // BPM이라는 변수에 state 불러오기
import { useDispatch} from "react-redux";
{...생략}
const dispatch = useDispatch();
우선 위와 같이 dispatch
를 사용할 수 있게 초기 설정을 해준다.
만약 버튼을 클릭시에 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
라는 선택지를 하나 더 얻었다고 생각하려고 한다. 다음 웹 서비스를 만들때, 이러한 선택지를 최대한 이용할 수 있을 것이라고 생각이든다.
좋은 글 감사합니다 🥸