[TIL 38] Redux, Context API

yezo cha·2021년 7월 9일
0

React

목록 보기
8/8
post-thumbnail

리액트에서 전역 상태를 관리할 때 많이 쓰는 ReduxContext API를 사용법과 장단점 위주로 비교해보자

전역 생태 관리 ?

상태 관리는 View 중심으로 이루어진 React Component에서 변하는 값에 대한 상태를 관리한다고 할 수 있다.

  • React의 useState를 사용하면 지역 상태 관리를 할 수 있다.
    • 사용하는 컴포넌트의 안 / props로 전달할 때만 하위 컴포넌트에서 사용할 수 있다.
  • 모든 상태 관리를 useState만을 사용해서 진행할 수도 있다.
    • 여러 컴포넌트에서 사용되는 상태라면 props로 하나씩 내려주기에 한계가 있다.
    • 이때 Context API, Redux와 같은 전역 상태 관리 도구를 사용한다.

What is Redux

리액트 생태계에서 가장 사용률이 높은 상태 관리 라이브러리.
Redux는 독립적으로 사용이 가능하고 자바스크립트 앱 안의 상태를 관리하기 위해 사용한다.
상태를 저장하는 store을 따로 가지고 있다.
Redux를 사용하면 컴포넌트들의 상태 관련 로직들을 다른 파일들로 분리시켜서 더욱 효육적으로 관리할 수 있고, 글로벌 상태 관리도 쉽게 할 수 있다.

Context APIuseReducer Hook을 사용해서 개발하는 흐름은 Redux를 사용하는 것과 매우 유사하다.

리덕스가 많이 사용된다고 해서 무조건 우리의 프로젝트에 리덕스가 필요한 건 아니다.
물론, 잘 사용한다면 프로젝트 개발 생산성에 아주 큰 도움을 줄 수도 있다.
하지만 단순히 글로벌 상태 관리를 위한 것이면 Context API를 활용하는 것으로 충분할 수 있다.

Redux 언제 써야 할까?

  1. 큰 규모의 프로젝트인가 ?
    • Yes : Redux.
    • No : Context API.
  2. 비동기 작업을 자주 하게 되는가?
    • Yes : Redux.
    • No : Context API.
  3. 리덕스를 배워보니까 사용하는게 편하다 !
    • Yes : Redux.
    • No : Context API / MobX

리덕스가 아무리 좋은 라이브러리라고 해도 취향에 맞지 않고 어렵게만 느껴지고 마음에 들지 않는다면 사용하지 않는 것이 좋다

  • 단순 전역 상태 관리만 있어도 괜찮다 ! : Context API
  • 디버깅, 로깅 등의 상태 관리 외의 기능이나 미들웨어가 필요하다 !! : Redux

Action

  • 상태가 변하는 것에 대한 액션을 함수로 작성한다.
export const focusChange = (payload) => {
  return {
    type: "FOCUS_CHANGE",
    payload,
  };
};
// action
// 유저 네임 변경하기, Post 추가하기
const changeUsername = (name) => {
    return {
        type: "CHANGE_NAME",
        name,
    };
};
const addPost = (post) => {
    return {
        type: "ADD_POST",
        post,
    };
};

Reducer

  • 초기 상태를 설정하고, actiontype으로 구별하여 상태를 업데이트하는 로직을 Reducer로 작성한다.
const initialState = {
  startDate: null,
  endDate: null,
  focusedInput: START_DATE,
};

const datePickerReducer = (state=initialState, action) => {
  switch (action.type) {
    case "FOCUS_CHANGE":
      return {
        ...state,
        focusedInput: action.payload
      };
    default:
      return state;
  }
};
// state
const initState = {
    name: 'yezo',
    posts: [],
};
// reducer
const reducer = (prevState, action) => {
    switch (action.type) {
        case "CHANGE_NAME":
            return {
                ...prevState,
                name: action.name,
            };

        case "ADD_POST":
            return {
                ...prevState,
                posts: [...prevState.post, action.post],
            };
        
        default:
            return prevState;
    }
};

Store

  • redux의 createStore를 통해 store의 인자에 생성한 Reducer를 넣어 생성한다.
  • 만약 Reducer가 여러 개라면, combineReducer를 통해 Reducer를 하나로 합치는 과정을 추가로 진행 해야 한다.
import { createStore } from 'redux'
// const { createStore } = require('redux');
const store = createStore(reducer, initState);
const store = createStore(reducer, initState);
console.log(store.getState());      // { name: 'yezo', posts: [] }
store.dispatch(changeUsername('차동동'));
console.log(store.getState());      // { name: '차동동', posts: [] }
store.dispatch(addPost('1'));
store.dispatch(addPost('앗....'));
store.dispatch(addPost('등록되나요?'));
console.log(store.getState());      // { name: '차동동', posts: ['1', '앗...', '등록되나요?'] }
store.dispatch(changeUsername('차보리'));
console.log(store.getState());      // { name: '차보리', posts: ['1', '앗...', '등록되나요?'] }

useSelector

  • 상태 값을 사용하고자 하는 컴포넌트에서 useSelector로 상태 객체를 꺼내서 사용할 수 있다.
import { useSelector } from 'react-redux'
const state = useSelector(state => state.itemReducer);

What is Context API

  • React에서만 사용 가능하다. (리액트 내장 기능)
  • Entry파일(root)에서 구성한 Provider를 내려 주는 형식.
  • 사용하고자 하는 컴포넌트에서 작성한 Dispatch와 State를 꺼내서 사용한다.
  • reducer를 여러 개 만들면 Provider에서 여러 단계로 만들어 사용할 수 있다.

Context

  • createContext를 통해 상태를 저장하게 된다.
  • initState초기 상태값을 객체 형태로 넣으면 된다.
import { createContext } from 'react'
const boardStateContext = createContext(initState);

Action

  • 액션을 지정해서 Reducer에서 서로 다른 타입일 때 다른 로직을 진행시킬 수 있다.
export type Action = {
  type: "UPDATE",
  payload
};

Reducer

  • action에 따라 state를 변경시키는 로직을 작성한다.
const reducer = (state, action) => {
  switch (action.type) {
    case 'CREATE_USER':
      return {
        users: state.users.concat(action.user)
      };
    case 'TOGGLE_USER':
      return {
        ...state,
        users: state.users.map(user =>
          user.id === action.id ? { ...user, active: !user.active } : user
        )
      };
    case 'REMOVE_USER':
      return {
        ...state,
        users: state.users.filter(user => user.id !== action.id)
      };
    default:
      return state;
  }
}

Provider

  • React의 useReducer에서 상태값dispatchvalue로 사용할 수 있다.
// State 용 Context 와 Dispatch 용 Context 따로 만들어주기
const UsersStateContext = createContext(null);
const UsersDispatchContext = createContext(null);

// 위에서 선언한 두가지 Context 들의 Provider 로 감싸주는 컴포넌트
export function UsersProvider({ children }) {
  const [state, dispatch] = useReducer(usersReducer, initialState);
  return (
    <UsersStateContext.Provider value={state}>
      <UsersDispatchContext.Provider value={dispatch}>
        {children}
      </UsersDispatchContext.Provider>
    </UsersStateContext.Provider>
  );
}
profile
(ง •̀_•́)ง

0개의 댓글