Redux_1

chloe·2020년 11월 10일
0

React

목록 보기
9/16

Redux?

자바스크립트 앱을 위한 예측 가능한 상태 컨테이너
리덕스는 자바스크립트를 위한 상태 관리 프레임워크.

Redux는 일관적으로 동작하고 서로 다른 환경에서 작동하고 테스트하기 쉬운 앱을 작성하도록 도와준다. 여기에 더해서 시간 여행형 디버거와 결합된 실시간 코드 수정과 같은 개발자 경험을 제공한다.

Why Redux?

애플리케이션의 모든 상태는 하나의 저장소 안에 하나의 객체 트리 구조로 저장된다.


🤹🏻‍♀️리덕스가 등장하게 된 배경을 살펴보자

1. MVC패턴

보통 개발자는 MVC(model-view-Controller)디자인 패턴을 활용하여 개발을 한다. 이런 MVC패턴은 애플리케이션 개발에 있어 매우 널리 사용되는 디자인 패턴이다. 그런데 이 패턴은 문제가 있었고 Facebook은 Flux라는 디자인 패턴을 정의하게 되었다.

controller는 model의 데이터를 조회하거나 업데이트 한다.
Model의 변화는 view에 반영된다. 또한 사용자는 view를 통해 데이터를 입력하는데, 사용자의 입력은 모델에 영향을 주기도 한다.

MVC패턴의 문제
Facebook같은 대규모 애플리케이션에서 MVC구조가 너무 빠르고 복잡해진다. 구조가 너무 복잡해지니 새 기능을 추가할 때마다 크고 작은 문제가 생겼다.페이스북이 찾은 근본적인 문제점은 애플리케이션에서의 데이터 흐름에 있었다. 사용자와 상호작용이 view를 통해 일어났기에 사용자 입력에 따라 view가 가끔씩 Model을 업데이트 해야할 필요가 있었다. 이러한 변경이 비동기적으로 생길 수도 있고 하나의 변경이 다수의 변경을 일으킬 수도 있었다.
데이터 흐름을 제대로 파악하고 디버그하기 어렵게 된 것이다.

2.Flux design pattern

해결책은 단방향 데이터 흐름에 있었다.
데이터는 단방향으로만 흐르고 새로운 데이터를 넣으면 처음부터 흐름이 다시 시작되는 방식으로 설계되었고 이 아키텍쳐를 Flux라고 불렀다.

아쉬운 flux의 문제점
1. 스토어의 코드는 애플리케이션 상태를 삭제하지 않고는 리로딩이 불가능..
flux에서 스토어는 다음과 같은 특성을 가진다
( 상태 변환을 위한 로직, 현재 애플리케이션의 상태)
==> 핫리로딩을 할 때 스토어 객체 하나가 위 2가지 특성을 가지고 있으면 문제가 발생한다.
2.애플리케이션 상태는 매 액션마다 재 기록된다.
데이터의 흐름이 단방향이기에 view는 Dispatcher에서 Action을 보낼 수 있고 Dispatcher는 동일하게 Action을 Store의 수정을 통해 View에 반영된다.


이러한 flux의 문제점을 보완하고 Redux 가 등장하게 되었다.
리덕스는 flux구조를 더 편하게 사용하기 위한 라이브러리다. 모든 데이터는 store에 저장되고 컴포넌트끼리는 직접 교류하지 않고 Dispatcher를 통해 Action을 발생시킨다. Component에서는 Store의 정보를 구독(subscribe)하고 있다가 데이터가 변동되었을 때 View를 리렌더링 해준다.

DOM과 DOM이 서로 직접적으로 연결되다 보면 복잡도가 상승한다.
state기반의 단방향 데이터 흐름을 통해 상태값과 레이아웃을 분리할 수 있게 됨
하지만 props drilling등의 문제로 인해 다시한번 성능하락 및 복잡도 상승 문제점 노출된다.


  • 각각의 컴포넌트 다 하나를 건들지 않아도 된다 (스토어에 저장을 하면 구조적으로도 간결하고 그리고 컴포넌트를 다 건드리면 다 렌더가 되니까 비효율적이니까 Redux가 왜필요한지 알게 된다!)

리덕스 사용시 따라야 할 3가지 원칙
1.전체 상탯값을 하나의 객체에 저장한다.
2.상탯값은 불변객체다.

상탯값은 오직 액션객체에 의해서만 변경된다.

const incrementAction={
  type:'INCREMENT',
  amount:123,
};
const conditionalIncrementAction={
  type:'CONDITIONAL_INCREMENT',
  amount:2,
  gt:10,
  lt:100.
};
store.dispatch(incrementAction);
store.dispatch(conditionalIncrementAction);
  • 액션 객체는 type속성값이 존재해야 한다.type속성값으로 액션 객체를 구분한다. type속성값을 제외한 나머지는 상탯값을 수정하기 위해 사용되는 정보다. 액션 객체와 함께 dispatch메서드를 호출하면 상태값이 변경된다.

리덕스의 상탯값을 수정하는 유일한 방법은 액션 객체와 함께 dispatch메서드를 호출하는 것이다.

3.상탯값은 순수 함수에 의해서만 변경되어야 한다.
리덕스에서 상탯값을 변경하는 함수를 리듀서라고 한다.

(state,action)=>nextState

리듀서는 이전 상탯값과 액션 객체를 입력으로 받아서 새로운 상탯값을 만드는 순수 함수.

뷰에서 액션 일으키고 디스패치일으키고 리듀서가 스토어를 업데이트 시키고 업데이트되면 뷰로 간다.

1)액션

  • type속성 값을 가진 자바스크립트 객체
  • 액션 생성함수는 그 액션 객체를 생성하는 역할을 하는 함수
  • 액션 객체를 dispatch 메서드에 넣어서 호출(useDispatch)
    (dispatch는 setState와 비슷한 개념)
  • 액션 생성함수가 생성한 액션 객체는 리듀서를 거쳐 스토어를 업데이트하게 된다.
export const addCart = (item) => { // 액션 "생성 함수"
  return {
    type: "ADD_ITEM", // 액션 "객체"
    payload: item, //add_item이라는 액션이고 payload는 변경가능한 key값. 타입속성 그내용을 말하는게 payload:item부분
  };
};

useDispatch

const dispatch =useDispatch()
  • 스토어의 내장함수로 스토어에 액션 객체를 전달하는 함수. (액션을 발생시키는 것이다)
  • dispatch의 인자로는 액션 객체를 전달해야 함
  • dispatch가 실행되면 액션 객체는 리듀서로 전달 되고 리듀서 내에 미리 정의해둔 조건문과 action.type에 따라 스토어가 업데이트 된다.

2) 리듀서(reducer)

이전의 스토어와 바꿔야할 액션을 통해 다음 state를 리턴하는 것이 reducer. 즉 리듀서는 액션이 발생했을 때 새로운 상탯값을 만드는 함수

(state, action) => nextState // state(혹은 store)와 action 객체를 받고 다음 state 리턴
// cartReducers.js
function cartReducer(state = INITIAL_STATE초기값, action) {
  switch (action.type) {
    case "ADD_ITEM":
      return [...state, action.payload]; // 스토어의 이전 상태에 새로운 item을 추가
		case "DELETE_ITEM":
			return [...action.payload]
    default:
      return state; // 해당 사항 없으면 이전 상태를 그대로 리턴
  }
}

// store/reducer/index.js
import { combineReducers } from "redux";
import cartReducer from "./cartReducer";

export default combineReducers({ cartReducer:cartReducer });
//리덕스에서 제공하는 함수 combineReducers(리듀서들을 합쳐주는 역할)
//cartReducer:cartReducer는 cartReducer로 줄여서 쓸 수 있음 

리듀서는 스토어랑 액션객체를 받아서 짬뽕해서 새로운 스토어를 리턴하는 함수
다만 그 안에 타입을 체크해서 조건문으로 타입에 맞는 로직을 실행하고 다음 state를 리턴한다.

  • 리듀서는 액션이 발생했을 때 새로운 상태값을 만드는 함수(그냥 js 함수)
  • 리덕스에서 스토어는 하나이다. 스토어라는 객체에 key,value로 넣어주면 된다.

3) 스토어

  • 스토어는 리덕스의 상태값을 가지는 단일 객체(하나)이며 프로젝트 어디서든 접근할 수 있다(Provider컴포넌트)_리액트 리덕스에서 제공하는 컴포넌트!
  • 액션=> 미들웨어=>리듀서=>스토어 업데이트=> 컴포넌트 업데이트

    스토어는 액션이 발생하면 미들웨어 함수를 실행하고 리듀서를 실행해서 상탯값을 새로운 값으로 변경한다.

useSelector

const items=useSelector(
  (store)=>{
    return store.cartReducer 
);

useSelector를 통해 store의 특정 내용을 가져올 수 있다.

🧐 Ducks Pattern?

기업협업 때, 리덕스 사용시 ducks pattern을 사용했다.
ducks pattern은 리듀서 함수, 액션 타입 함수, 액션 생성 함수를 하나의 파일에 작성하는 방식이다

Ducks 구조의 규칙
1.항상 reducer()란 이름의 함수를 export default해야한다.
2.항상 모듈의 action 생성자들을 함수형태로 export해야 한다.
3.항상 npm-module-or-app/reducer/ACTION_TYPE형태의 action타입을 가져야 한다.
4. action 타입들을 UPPER_SNAKE_CASE로 export할 수 있다.
=> Ducks구조는 기능 중심으로 파일을 나눈다. 이 구조가 가지는 장점은 단일 기능을 작성할 때나 바뀌었을 때에 하나의 파일만 다루면 되니까 좀 더 직관적인 코드 작성이 가능하다.

참고: WECODE

profile
Front-end Developer 👩🏻‍💻

0개의 댓글