React ContextAPI 와 Redux Toolkit

wisdom·2022년 5월 20일
0
post-thumbnail

SPA 단점

  • 컴포넌트 간 state 공유가 어렵다.
    • 부모 컴포넌트 -> 자식 컴포넌트 props 전송만 가능
  • props를 제외하고, state를 공유할 수 있는 방법?
    • 전역 상태 관리 도구
      • Context API
      • Redux 등 외부 라이브러리

ContextAPI

  • props 전송없이 state를 공유할 수 있게 도와주는 리액트 기본 문법
  • 여러 컴포넌트가 중첩된 경우에 사용하면 props를 두 번, 세 번 복잡하게 전달(Prop Drilling) 하지 않아도 된다는 장점이 있다.
    • Prop Drilling의 단점?
      • 단계적으로 전달해야하기 때문에 Prop을 쓰지 않는 중간 단계의 컴포넌트도 거쳐가야 한다.
        • 중간에 수정될 가능성도 존재
  • 전역적으로 쓰이는 Global Data인 User, Theme, Language 등이 있을 때 props 를 이용해서 단계적으로 데이터를 전달해야한다면?
    • 코드도 복잡해지고, 한 번 수정할 때 일일이 각 컴포넌트에서 수정해줘야 한다.
  • 그런데 잘 쓰지 않는다. 왜?
    • [ContextAPI 특징]
      • state 변경 시, 전달된 state를 안 쓰는 컴포넌트까지 불필요하게 재렌더링 -> 성능 이슈
      • 컴포넌트 재활용이 어렵다는 단점

사용법

  1. context를 만들어준다. (state 보관함)
let myContext= createContext() 
  1. 컴포넌트 감싸고 공유하고 싶은 state 집어 넣기
<myContext.Provider value={{state1, state2 ...}}> 
    <Detail/> // 여기 감싸진 컴포넌트는 {{ }} 두 개의 중괄호에 들어 있는 state들을 사용할 수 있다. 
</myContext.Provider>
  1. 컨텍스트변수명.Provider로 감싸진 내부의 컴포넌트에서 state를 사용하기 위해서는?
    • Context를 import
    • useContext(컨텍스트변수명)
      • state 보관함을 사용할 수 있게 해체해준다.
  • 컨텍스트변수명.Provider로 감싸진 내부의 컴포넌트(Detail)뿐만이 아니라 그 컴포넌트의 자식들(중첩된 컴포넌트)도 props 없이 사용가능하다.

✅ Context는 꼭 필요할 때만 써야 한다. Prop Drilling을 피하기 위한 목적이라면 Component Composition을 먼저 고려해보라고 공식문서에서 제안하고 있다.


Redux Toolkit

  • props 전송없이 state를 공유할 수 있게 도와주는 라이브러리
  • JS 파일 하나에 state를 보관하고, 그걸 모든 컴포넌트가 직접 꺼내서 쓸 수 있다.

왜 쓸까?

  • 컴포넌트 간 state 공유가 편해진다.

사용법

  1. store.js 파일 생성
import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: { }
}) 
  1. index.js
<Provider store={store}>
    <BrowserRouter>
        <App/>
    </BrowserRouter>
</Provider>

✅ 컴포넌트 간 공유가 필요한 경우에만 Redux store에 넣는다. 컴포넌트 간 공유가 필요없으면 useState() 쓰면 된다.

Redux의 state 변경하는 법

  1. state가 보관된 파일(store.js)에서 state 변경해주는 함수(action) 만들기
 reducers: {
        changeName(state) {
            return 'wisdom' + state
         }
    }
  1. 만든 함수 export
export let {state변경함수, ... } = 변수명.actions
  1. 변경하고 싶을 때 그 함수 실행해달라고 store.js에 요청
let dispatch = useDispatch();
...
dispatch(state변경함수())
  • array/object의 경우 직접 수정해도 state 변경된다.
    • immer.js 도움
 reducers: {
        changeName(state) {
            return state.name = 'park'
        }
    }

왜 이렇게 복잡하게 수정할까?

✅ redux 사용 방식이다. 변경해주는 함수없이 이 컴포넌트, 저 컴포넌트에서 state를 마구잡이로 변경할 경우, 문제가 생길 가능성이 크다. 그리고 그 문제를 어디서 발생한건지 추적하기가 매우 어려울텐데 변경 함수를 씀으로써 state를 보관하는 파일만 확인하면 된다.


추가 내용

useReducer

  • 복잡한 state를 다뤄야할 때, useState 대신 사용한다.
  • 구성 요소
    • Reducer
      • state update 해주는 역할
    • Dispatch
      • Reducer에게 update 해달라고 요구하는 역할
    • Action
      • Dispatch에 들어가는 내용(요구의 내용)

왜 쓸까?

  • 사용하는 쪽에서는 복잡한 로직을 처리하지 않아도 된다.
    - 복잡한 상태를 바꾸는 것은 전문화된 reducer 함수가 처리할 수 있게 된다.
  • 그리고 state 이전의 값과 이후의 값이 서로 상당한 관계가 있을 때 reducer를 사용하면 상태를 변경시키는 과정을 reducer 함수 안에 은닉할 수 있다는 장점

useReducer + useContext

  • useReducer와 useContext를 조합하여 사용하면 redux 패턴을 흉내낼 수 있다. 어떤 depth에 위치한 컴포넌트든 useContext와 action dispatch로 state를 읽어오고 수정할 수 있다.

✅ useRedcuer로 만든 state와 dispatch를 useContext를 이용해 하위 컴포넌트들이 사용할 수 있게끔 만드는 것이다.

profile
문제를 정의하고, 문제를 해결하는

0개의 댓글