React

[React 공부] Context API 전역값 관리 & Immer 사용 불변성 관리

코딩굼벵이 2022. 7. 5. 15:20
728x90
 

22. Context API 를 사용한 전역 값 관리 · GitBook

22. Context API 를 사용한 전역 값 관리 이번에 사용되는 코드는 다음 CodeSandbox 에서 확인 할 수 있습니다. 우리가 현재 만들고 있는 프로젝트를 보면, App 컴포넌트에서 onToggle, onRemove 가 구현이 되어

react.vlpt.us

Context API

프로젝트의 상태, 함수, 외부 라이브러리 인스턴스, DOM까지도 관리 가능

- 새로운 Context 생성

const UserDispatch = React.createContext(null);

 

- Context를 만들면 안에 들어있는 Provider라는 컴포넌트로 Context의 값을 정할 수 있음.
컴포넌트 사용 시 value라는 값을 설정해주면 됨.

<UserDispatch.Provider value={dispatch}>…</UserDispatch.Provider>

 

=> Provider로 감싸진 컴포넌트 전역에서 Context 값을 조회하고 사용 가능

export const UserDispatch = React.createContext(null);

 

로 내보내주면 나중에 사용하고 싶을 때

import React, { useContext } from 'react';
import { UserDispatch } from ‘./App’;

...
const dispatch = useContext(UserDispatch);
...
<button 
    onClick={() => {
    dispatch({ type: 'REMOVE_USER', id: user.id });
}}>삭제</button>

 

처럼 불러와서 사용 가능 (위의 예시에서는 내보낸 파일 위치에서 useReducer 및 reducer 함수에서 switch로 분기한 설정을 사용 중)

 


 

23. Immer 를 사용한 더 쉬운 불변성 관리 · GitBook

23. Immer 를 사용한 더 쉬운 불변성 관리 리액트에서 배열이나 객체를 업데이트 해야 할 때에는 직접 수정 하면 안되고 불변성을 지켜주면서 업데이트를 해주어야 합니다. 예를 들자면 다음과 같

react.vlpt.us

Immer

리액트에서 배열이나 객체 업데이트 시 직접 수정 X. 불변성 지켜주면서 업데이트 해줘야 함

  • 객체: spread 연산자 사용
  • 배열: concat, filter, map 등의 함수 사용 (ex. push, splice 등 사용한 항목 직접 수정 X)

데이터 구조가 까다로워지면 불변성 지키면서 새로운 데이터 생성하는 코드가 복잡해짐

=> Immer 라이브러리 쓰면 상태 업데이트 할 때 Immer가 불변성 관리 대신 해줌

- 라이브러리 설치 후 선언 필요

yarn add immer

import produce from ‘immer’;

- produce 함수 사용 시)
첫번째 파라미터: 수정하고 싶은 상태
두번째 파라미터: 어떻게 업데이트 할지 정의하는 함수

- 함수형 업데이트를 하는 경우에도 Immer 사용하면 편리

- produce 함수에 파라미터 2개 넣으면: 첫번째 파라미터에 넣은 상태 불변성 유지하면서 새로운 상태 만들어줌.
첫번째 파라미터 생략하고 파라미터로 업데이트 함수만 넣으면: 상태 업데이트 해주는 함수가 반환값이 됨.

- 단, 사용하면 간단해지기도 하지만 오히려 코드가 길어질 때도 있음.

- 성능적으로는 Immer를 사용하지 않은 코드가 조금 더 빠름.

- JavaScript 엔진의 proxy 기능을 사용하는데, 구형브라우저나 react-native 환경에서는 지원 X
=> ES5 fallback 사용하게 되는데 이게 꽤나 느려짐

∴ 가능하면 데이터의 구조가 복잡해지게 되는 것을 방지하기. 무조건 사용하지는 말고 '어쩔 수 없을 때' 사용하기

예시 코드 1)

const state = {
    number: 1,
    dontChangeMe: 2
};

const nextState = produce(state, draft => {
    draft.number += 1;
});

 

예시 코드 2)

const nextState = produce(state, draft => {
    const post = draft.posts.find(post => post.id === 1);
    post.comments.push({
        id: 3,
        text: ‘쉬운 추가’
    });
});

 

↓ Immer를 사용하지 않은 코드와 비교

더보기

불변성을 지키기 위한 노력이 필요

const nextState = {
  ...state,
  posts: state.posts.map(post =>
    post.id === 1
      ? {
          ...post,
          comments: post.comments.concat({
            id: 3,
            text: '새로운 댓글'
          })
        }
      : post
  )
};

 

- 유저를 삭제하는 코드로 비교해보기

Immer 미사용 - 선택한 유저만 제외해서 필터링

return {
      ...state,
      users: state.users.filter(user => user.id !== action.id)
};

 

Immer 사용 - 선택한 유저의 인덱스를 받아와 삭제

return produce(state, draft => {
       const index = draft.users.findIndex(user => user.id === action.id);
       draft.users.splice(index, 1);
})