본문 바로가기
WEB/기초

[WEB] React, Redux - 1

by IT황구 2021. 7. 26.
728x90
반응형

https://blog.naver.com/rbals0445/222444529706

 

[WEB] React, Flux Architecture

아!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 이번에 강의 들으면서 Redux 배웠는데, 굉장히 깔끔한것 같더라구요. ...

blog.naver.com

 

지난시간에 이어서, Redux 한편 뽑겠습니다 ^^

 

npm install redux;

npm install react-redux;

 

이렇게 설치를 합시다!!

 

Redux (상태 관리 컨테이너)
이녀석 죽입니다..

 

react-native로 뭘 만들고 있는데.. data를 맨날 route로 넘기니까 코드 짜는것도 불편하고 너무 지저분 했습니다. 근데 이걸 미리 알았더라면..

정말 아름다운 구조입니다. 한번 똥을 싸보니까 신세계를 봤을때 이게 얼마나 소중한지 알겠더라고요.

기업에서 모집할때 Mobx나 Redux를 사용한다는 이유를 알겠습니다.

 

일단, 왜 쓰는지? 에 앞서서

Redux의 Core Concept에 대해서 알아보겠습니다.

1. Sigle source of Truth

-> 그대로 갖다 옮겼습니다. 음... 신뢰의 단일 소스? 이걸 어떻게 해석해야 하는지..

저는 유일한 store에서 state를 관리해서 믿을만한 한개의 스토어? 이렇게 받아들였습니다

1개의 single store를 두면 중앙화된 로직 처리로 디버깅도 편하고, 전체 app과 interact할 때 state를 보기 편하기 때문입니다.

 

2. State is Read-Only

-> 이건 react의 state와 같죠? read-only라서 값이 절대 직접 바뀌면 안됩니다.

dispatch를 통해서 값을 복사해서 바꾸고, 저장을 합니다.(직접 안바꿨죠?)

계속 새로 값을 할당해준다고 보면 됩니다. 실수로 값을 덮어쓰거나 이런것을 방지할 수 있습니다. 또한 예상치 못한 state update를 추적하는데 많은 도움을 줍니다.

 

3. pure Reducer funtion에 의해서만 변화가 일어나야 합니다

-> 지금 나오는 용어들은 아래에 다 설명하겠습니다.

reducer를 써서 state가 어떻게 변경되는지 구체화 하려면, 순수함수를 써야 추적이 더 쉽기 때문입니다.

순수함수는 저번에 포스팅을 했습니다. 특정 parameter에는 특정 return만 나옵니다. return이 변하면 안됩니다.

 

예시) f(1) = 3, f(1) = 5 이런식으로 계속 바뀌면 추적이 힘들지만, f(1)=3 만 나온다면, 야!! 3 나오게 한거 누구야? 하면 바로 범인 검거 가능합니다.

 

Redux는 그럼 왜 쓸까요?

항상 필요한것은 아닙니다. 코드가 짧고 간단한 프로그램이면 굳이? 쓸 이유가 없습니다.

하지만, 프로그램의 규모가 커지고 컴포넌트가 많아져서, 관리해야 할 state가 많아지면 redux가 굉장히 좋습니다.

redux의 핵심 concept처럼 redux는 store에서 state를 global로 관리하기때문에, 필요한 컴포넌트에서 불러서 그냥 쉽게 쓸 수 있습니다.

state를 바꿀때마다 영향을 받는 view들을 자동으로 업데이트 해주기때문에 굉장히 편리하다고 할 수 있습니다.

 

react-redux

redux는 react만을 위한 패키지가 아닙니다. 다른 라이브러리나 프레임워크에도 잘 붙어서 쓸 수 있기때문에

react와 binding한 패키지입니다. 이걸 설치하면 여러 기능들을 사용할 수 있습니다.

 

Data 흐름도

 

용어 설명에 앞서서, 어떻게 데이터가 흐르는지 보여드려야 합니다.

https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow

 

순서 :

1. UI(View)에서 event가 발생합니다. 그러면 Event handler로 event 내용이 갑니다.

2. 이벤트 핸들러에서는 dispatch method에 Action(이벤트 내용) 을 담아서 Store로 보냅니다

3. Store에서는 reducer가 (현재의 state, Action) 을 받아서 새로운 state를 리턴합니다.

4. 그 새로운 state는 view로 보내져서 view를 re-render 합니다.

 

flux-architecture와 굉장히 유사하죠? 하지만 차이도 있습니다.

하지만 얘는 배달원 dispatcher도 존재하지 않고, reducer도 여기만 있답니다.

 

 

용어 설명 (자세합니다)

1. Action

action은 type field를 가지고 있는 순수 js object 입니다. (app에서 일어나는 어떤 이벤트를 묘사하는 것이라고 생각하면 됩니다)

(ex : 유저를 삭제하자, 숫자를 올려라)...

 

1-1.

Action의 type field는 string으로 써야합니다.

일반적으로 type: "todos/todoAdded" 이런식으로 쓰는데,

첫 부분은 카테고리나 특징을 쓰고 두번째 부분은 구체적으로 어떤 행위인지 작성합니다.

descriptive 하게 쓰는게 좋습니다.

만약 추가적인 설명이 필요하면 payload field를 추가해서 내용을 더 담을 수 있습니다.

왜 payload 냐고요? convention 입니다. 다른걸로 해도 되긴 합니다. 근데 초록불을 나 혼자 노란불이라고 할 수는 없죠? 언어의 사회성에 대해서 생각해봅시다 .. 여기까지..

 

const addAction = {

type : "todos/todoAdded",

payload : "Buy milk"

}

이런식으로 쓰는게 좋답니다.

 

2. Reducer

위의 flow에서 보면 더 와닿는데, reducer는 state와 action을 받아서 새로운 state를 return합니다.

나중에 예제 코드를 보면 어떤 형식인지 알 수 있습니다.

참고로 pure function 이어야 합니다. (parameter와 return 값이 항상 일정한것, 매번 값이 바뀌는게 아닙니다)

 

**Array.reduce()와 유사한 동작이라서 reducer로 했다고 하더라구요. 오우!!

 

Reducer에는 무적권(필살기) 따라야하는 rule이 존재합니다.

이걸 안따르고 왜 안되냐고 하면 안됩니다

1. return하는 new state는 무조건!! (state,action) parameter로 주어진것만 고려해서 업데이트 해야합니다.

자기 맘대로 msg 섞고 다른 state 불러다가 더하고 그렇게 하면 안됩니다.

 

2. 현재의 state를 바로 modify 하는건 절대!!! 안됩니다 copy를 해서 copy한 변수를 수정하는 방식으로 해야합니다.

(절대 직접 건들지 마세요, read-only에 대해서 생각해봅시다)

 

3. 어떤 비동기처리, 랜덤 숫자 계산, 또 다른 부수효과(side effect)를 발생시키는 일들을 하면 안됩니다.

-> 여기는 아직 체감을 안해봐서 잘 모르겠네요

 

Reducer의 내부는 어떻게 돌아가는지 한 번 봅시다.

action에서 type을 정해서 보냅니다.

그러면 reducer 내부에서는 action.type === "내가 받은 type" 을 비교해서, 같은 타입이면 state를 copy하고 새로운 값을 넣어서 return 합니다. 무적권(필살기) 2번에 해당하는 내용입니다.

 

return{ ...state , state : state.value +1}

이런식으로 합니다. 이거 어디서 많이 봤죠? useState에 parameter를 Array로 줬을때 기존의 배열을 복사하고 변경을 했잖아요?

state는 read-only라서 아예 새로 갱신을 하는거라서 그렇습니다.

 

3.Store

store에는 현재 Redux application state가 존재하고 있습니다.

store는 createStore함수로 만들어지는데 parameter가 reducer라서 reducer에 의해서 만들어진다고 볼 수 있습니다.

 

즉 순서는

action, state로 reducer를 생성합니다. 이 reducer에 의해서 store가 생성됩니다.

그리고 getState로 store에서 현재의 state를 받아올 수 있습니다.

 

4. Dispatch

Redux store은 dispatch라는 method가 존재합니다.

오직!! store.dispatch(action object)에 의해서만 state를 update 할 수 있습니다.

dispatch가 이벤트를 발생시킨다고 봐도 됩니다.

 

그러면 reducer가 action과, 현재의 state를 받아서 새로운 state를 반환합니다.

반환 후에 그 state는 store에 저장이 되고, 저장이 되면 우리는 store에서 getState()를 이용해서 값을 가져 올 수 있습니다.

 

5. Selectors

store state value를 어떻게 추출할 지 알고있는 함수입니다.

custom hook인 useSelector로 store의 state를 받아올 수 있더라구요.

근데 이게 반복호출을 피해준다는데, 이게 무슨말인지 아직은 잘 와닿지 않습니다.

간단한 사용을 보여드리겠습니다.

Class component로 하면 무슨 connect()를 통해서 subscribe하는 container component를 생성하기도 해야합니다.

connect의 parameter가 2개가 있습니다.(optional)

1. mapStatetoProps(): store state가 변할때마다 호출된다.

각각의 필드가 wrapped component를 위한 prop이 된 object를 리턴한다. (연결된 모든 component들에서 props로 가져다 쓸 수 있다)

 

2. mapDispatchToProps(): dispatch() methods를 받아서, dispatch를 사용하는 function으로 가득찬 object를 return해야한다.

 

class로 해보니까 복잡하더라구요.

 

functional Component를 이용하면 useSelector로 쉽게 할 수 있습니다.

보여드리겠습니다.

 

일단 먼저 reducer를 생성하겠습니다.

action과 state가 필요하겠죠?

 

이렇게 초기 state를 설정해주고, reducer를 생성합니다.

action은 일단 없지만, state에는 initValue를 초기값으로 넣어주도록 하겠습니다.

사실 react docs에는 state = initValue를 장려하진 않더라구요.

근데 아직 안되는 경우는 못봐서 이대로 하겠습니다.

import { DISHES } from "../shared/dishes";
import { COMMENTS } from "../shared/comments";
import { LEADERS } from "../shared/leaders";
import { PROMOTIONS } from "../shared/promotions";

export const initValue = {
  dishes: DISHES,
  comments: COMMENTS,
  leaders: LEADERS,
  promotions: PROMOTIONS,
};

export const reducer = (state = initValue, action) => {
  return state;
};

 

reducer와 state도 있으니까 이제 store를 만들어보겠습니다.

// store과 reducer
import { createStore } from "redux";
import { initValue, reducer } from "./reducer";
//state
export const configureStore = () => {
  const store = createStore(reducer, initValue); // reducer,preloadstate
  return store;
};

이런식으로 createStore로 store를 생성해서 리턴합니다.

createStore( 리듀서 함수, 미리 불러올 state) 이렇게 됩니다. 참고로 2번째 파라미터는 선택입니다. 안줘도 됩니다.

 

먼저!!

App.js로 가서 최상위 컴포넌트를 <Provider>로 감싸줍시다.

<Provider의 parameter는 store입니다>

이것의 역할은 무엇일까요?

이렇게 최상위 컴포넌트에 store를 선언해줘서, 하위 컴포넌트들이 필요할때 자유롭게 store에 접근할 수 있도록 하는 것 입니다.

 

 

이런식으로 useSelector hook을 이용하면 store에 있는 값을 쓸 수 있습니다.

useSelector가 어떤 값을 반환하는지 볼까요?

 

value를 찍어보니 object가 있습니다.

이제 우리는 View에서 values.dishes , values.leaders 이런식으로 직접 접근할 수 있게 됩니다.

 

이전에는 this.state 이런식으로 값을 쓰려면 props로 여러번 넘기고 이런식으로 해야했습니다.

하지만 redux를 이용해서 store에서 값을 가져오니 굉장히 편하죠?

state관리가 편한것도 정말 좋은 것 같습니다.

 

 

---끝

reference -

모든 내용은 아래 자료를 보고 작성을 했습니다.

 

https://redux.js.org/tutorials/fundamentals/part-5-ui-react#passing-the-store-with-provider

 

Redux Fundamentals, Part 5: UI and React | Redux

The official Redux Fundamentals tutorial: learn how to use Redux with React

redux.js.org

 

 

728x90
반응형