반응형

원래 redux를 처음에 공부하다가 

부스트캠프에서 프로젝트할때 recoil를 도입해서 사용했었는데

recoil이 나온지 얼마 안되다보니

redux의 기본적인 틀에 대한 코드만 메모해두려고 한다.

 

redux의 핵심 개념 - flex 패턴

 

사용자와 상호작용을 하다보며 view가 가끔씩 state을 업데이트해나갈때가 있는데,

그 영향이 다른 view나 state를 연쇄적으로 업데이트해서 서로 상호작용을 일으켜 의도치 않은 

버그나 결과를 내놓는 경우가 있었다

 

즉, 공을 튀기면 어느곳으로 튕겨나갈지 모르는 연쇄적인 반응이 일어났던것이다.

그래서 연쇄적 업데이트를 방지하고 단방향 데이터 흐름인(undirectional data flow) 인 flex 패턴이 탄생했다.

redux는 flex 패턴을 활용한 유명한 라이브러리이다.

 

Flux는 단방향으로 데이터가 흐르게 하는 구조이다.

redux는 크게 4가지 파트로 이루어져 있다.

 

상태 변경 정보인 Action

Action을 Store 에 반영하는 Dispatcher

Action을 처리해서 상태를 변경시키는 reducer

상태를 저장하는 Store

 

 

view layer에서 상태를 변경하고 싶다면 정해진 Action을 dispatch에 담아 호출한다. 

그럼 Reducer에서 그 액션을 처리하고 상태를 변경하여 store에 반영한다.

 

이제 연쇄적인 양방향 데이터 흐름을 단방향 데이터 흐름으로 바꾸었고, side effect가 없는

순수함수적인 개념으로 동작한다.

 

 

 

 

그림이니 눌러도 작동 안합니다 😂

그럼 버튼을 누르면 숫자가 늘어나거나 줄어드는 간단한 화면을

코드로 구현해보자.

Action

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

 

Action 명은 그냥 unique한 식별자를 가진 이름으로 구현하면 된다.

옛날에 수학 시간에 배운 함수를 떠올려보자.

 

함수 F 에 x 를 넣으면 y가 나온다는 수학 공식을 떠올리면

항상 같은 x를 넣으면 같은 y가 나온다.

F(x)=y

 

정해진 Action과 파라미터를 dispatcher에 넣으면 (상태가 같다면) 항상 같은 결과가 나오는것을 기대할 수 있어야 한다.

즉, 함수형 패러다임 개념을 일부 가져왔다.

강제된 법칙은 아닐테지만 의도치않은 버그를 보고싶지 않다면 따르는것이 좋다.

 

function increment(value: number) {
  return { type: INCREMENT, payload: { value } };
}

function decrement(value: number) {
  return { type: DECREMENT, payload: { value } };
}

해당 방식으로 action과 payload를 미리 정의할수도 있다.

payload는 action 이외에 view에서 받고 싶은 파라미터이다.

 

간단한 수학공식으로 예를 들면

F(x, a) = x + a 라고 볼 수 있다.

 

reducer

const initState = {
  value: 0,
};

const reducer = (state = initState, action) => {
  const { type, payload } = action;
  const { value } = state;

  switch (type) {
    case INCREMENT:
      return { ...state, value: value + payload.value };
    case DECREMENT:
      return { ...state, value: value - payload.value };
    default:
      return state;
  }
};

 

reducer는 state와 action을 받아서

알맞은 action에 따라 연산을 한 후 값을 반환한다.

 

아까 설명한 F(x)=y 의 함수(F) 역할을 하는 셈이다.

state의 초기값은 매개변수로 넣은 객체값이고, 이후 리둑스 라이브러리에서 자체적으로 관리와 갱신을 해주게 된다.

그리고 switch문 내부 가독성을 위해

case문 하나 하나 함수를 구현하는것을 추천한다.

store

const store = createStore(
  combineReducers({
    reducer,
  }),
);

store는 리엑트의 '전역' 상태 state라 보면 이해가 편하다.

store는 한개만 있어야 한다. (a single source of truth)

 

만약 reducer를 너무 크게 만들지 않고 기능별로 쪼개고 싶다면 combineReducer를 활용해서 합친다.

 

dispatcher

 

import { Provider, useDispatch, useSelector } from 'react-redux';

function Test() {
  const { value } = useSelector((state) => state.reducer);
  const dispatch = useDispatch();

  return (
    <div>
      <button
        onClick={() => dispatch({ type: INCREMENT, payload: { value: 10 } })}
      >
        up 1
      </button>

      <button onClick={() => dispatch(increment(10))}>up 10</button>
      <button
        onClick={() => dispatch({ type: DECREMENT, payload: { value: 10 } })}
      >
        down
      </button>

      {value}
    </div>
  );
}

ReactDOM.render(
  <Provider store={store}>
    <Test />
  </Provider>,
  document.getElementById('root'),
);

 

dispatcher는 미리 action을 받아서 reducer를 통해 상태를 갱신한다.

함수형 컴포넌트에서 react-redux 의 useSelector, useDispatch hook을 사용하면 쉽게 구현 가능하다.

 

      <button onClick={() => dispatch(increment(10))}>up 10</button>
      <button onClick={() => dispatch({ type: DECREMENT, payload: { value: 10 } })}>
        down
      </button>

위 코드 중간에 해당 방식처럼 dispatch에 넣는 방식으로는 함수를 쓸 수도 있고, 아니면 객체 리터럴을 정해진 형식대로 그대로 넣어도 된다.

 

(무슨 방식이든 내가 기존에 구현했던 reducer와 매칭이 잘되야 한다.)

 

나는 미리 구현된 함수를 넣는 방식을 추천한다.

남이 봤을때 dispatch만 봐서 무슨 역할을 하는지 이해가 어려울 수 있는데,

잘 명시된 함수 명으로 힌트를 주는 방식으로 구현하는게 유지보수및 협업 측면에서 좋다고 생각된다.

(위 코드는 예시 코드이니 함수명이 매우 간결하다 😂)

 

그외

 

개인적으로 

action, state, reducer 등을 한 파일에 몰아넣지 말고 

각각 모듈화해서 분리(action은 action끼리, reducer는 reducer 끼리)해서 파일구조를 짜는걸 추천한다.

 

그리고 redux-toolkit 이라는 redux를 보다 쉽게 사용 가능하게 도와주는 라이브러리도 있다.

다른 라이브러리는 redux 기반으로 설명 되어 있는 글이 많아서 처음 배우고 있을때 보면 엄청 헷갈린다.

redux가 어느정도 익숙해지면 나중 생산성 향상을 위해 도입해보는거도 나쁘지 않는거 같다.

 

같이 읽어보면 좋을 글)

 

전역 상태를 왜 쓰는지 -> props drilling 해결

https://medium.com/front-end-weekly/props-drilling-in-react-js-723be80a08e5

 

Props Drilling In React.Js

What Is Props Drilling? And How To Sidestep It?

medium.com

 

기존 react는 (model이 없는) VVM 혹은 VC 패턴이라고 보는게 정확하다는 의견도 있다.

https://stackoverflow.com/questions/51506440/mvvm-architectural-pattern-for-a-reactjs-application

 

MVVM architectural pattern for a ReactJS application

I'm a semi-senior react and JavaScript developer, I've made several Universal react application. Today our CTO told me: Do you use a software architectural pattern for your application? I've no a...

stackoverflow.com

 

reference

 

https://redux.js.org/tutorials/fundamentals/part-1-overview

 

Redux Fundamentals, Part 1: Redux Overview | Redux

The official Fundamentals tutorial for Redux: learn the fundamentals of using Redux

redux.js.org

 

 

https://sihus.tistory.com/37

 

Flux Design Pattern 이해하기 (+ 단방향, 양방향 데이터 바인딩)

MVC 디자인 패턴이 아닌 Redux의 주개념이자, 리액트를 사용하면서 컴포넌트끼리 데이터를 교류할 때, 글로벌 이벤트 시스템을 설정하는 방법인 Flux 디자인패턴에 대해 알아보고 왜 facebook에서 reac

sihus.tistory.com

 

https://yoonho-devlog.tistory.com/171

 

Redux 개념 이해하기

Flux 패턴 redux는 Flux 패턴의 구현체입니다. 따라서 Flux 패턴을 먼저 이해하면 자연스럽게 Redux를 이해할 수 있습니다. facebook은 우리가 흔히 알고 있는 MVC 패턴을 사용하는 대신, Flux라는 새로운 방

yoonho-devlog.tistory.com

 

https://hanamon.kr/redux%EB%9E%80-%EB%A6%AC%EB%8D%95%EC%8A%A4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC/

 

Redux(리덕스)란? (상태 관리 라이브러리) - 하나몬

Redux(리덕스)란? 무엇인지 부터 간단한 실습까지 (상태 관리 라이브러리 리덕스 알아보기) ⚡️ Redux(리덕스)란? Redux(리덕스)란 JavaScript(자바스트립트) 상태관리 라이브러리이다. Redux(리덕스)의

hanamon.kr

 

 

반응형

'Front-end > React' 카테고리의 다른 글

react 17(개인 공부용)  (1) 2022.06.09
React18(개인 공부 메모용)  (0) 2022.06.09
react TMI  (0) 2022.04.13
drag and drop으로 창 크기 조절  (0) 2022.03.18
redux, redux-saga로 로딩, 에러 페이지 구현  (0) 2022.02.12

+ Recent posts