React.js useState만으로 Context API 를 구현하기

강정우·2023년 10월 19일
0

react.js

목록 보기
45/45
post-thumbnail
post-custom-banner

Context API의 단점

  • 앞서 포스팅 했듯 context의 한계점은 명확하다.

  • 또 극한의 성능충들은 대규모 플젝이 아닌이상 굳이 서드 파티 라이브러리까지 끌어와서 사용할 이유가 없다고 생각할 수 있다.

  • 그래서 성능충(나)를 위한 useState만으로 Context API 커스텀 훅 구현하기를 시작해보겠다.

Store 훅 만들기

  • 잊어버렸을 까봐 말하는데 커스텀훅의 특징 중 하나는 커스텀훅을 사용하면 state화 하여 해당 컴포넌트에만 "tied" 된다고 하였다.
  • 여기서의 커스텀 훅은 데이터를 공유하기 위하여 따로 let 변수로 선언하여 app scope의 데이터 저장소를 만드는 것이다.

data

let globalState = {};
let listeners = [];
let actions = {};
  • 저기서 listeners가 갖는 의미는 호출했을 때 훅을 사용하는 모든 컴포넌트 함수로 이루어진 배열이다.
  • actions는 store에 대한 구체적인 용도를 각각의 액션으로 정의될 것.

등록하면 등록, 코드를 삭제하면 등록해제

export const useStore = (shouldListen = true) => {
  const setState = useState(globalState)[1];			// 1.

  useEffect(() => {											// 2.
    if (shouldListen) {
      listeners.push(setState);										// 3.
    }

    return () => {
      if (shouldListen) {
        listeners = listeners.filter(li => li !== setState);				// 4.
      }
    };
  }, [setState, shouldListen]);

  return [globalState, dispatch];
};
  1. 여기 store에서는 set함수만을 사용하기위해 따로 잘라서 구현하였다.
  2. effect를 쓰는 이유는 의존성에 맞춰서 컴포넌트를 재평가하여 해당 커스텀훅이 더이상 사용되지 않는다면 없애기 위해서이다.
  3. 현 커스텀훅을 사용하는 모든 컴포넌트들 자기만의 setState함수를 갖고 이를 한 배열에 공유한다.
  4. 해당 커스텀훅이 더이상 사용되지 않는다면 없애기 위해서의 구현부이다.

state에 맞춰 업데이트

import { useState, useEffect } from 'react';

let globalState = {};
let listeners = [];
let actions = {};

export const useStore = (shouldListen = true) => {
  const setState = useState(globalState)[1];

  const dispatch = (actionIdentifier, payload) => {					// 1.
    const newState = actions[actionIdentifier](globalState, payload);				// 2.
    globalState = { ...globalState, ...newState };
    for (const listener of listeners) {				// 3.
      listener(globalState);
    }
  };
  useEffect(() => {
    if (shouldListen) {
      listeners.push(setState);
    }

    return () => {
      if (shouldListen) {
        listeners = listeners.filter(li => li !== setState);
      }
    };
  }, [setState, shouldListen]);

  return [globalState, dispatch];
};


export const initStore = (userActions, initialState) => {			// 4.
  if (initialState) {
    globalState = { ...globalState, ...initialState };
  }
  actions = { ...actions, ...userActions };
};
  1. state를 바꾸기위한 디스패치 함수
  2. 마치 리듀서처럼 액션의 키값으로 접근하여 state를 최신화 시켜주는 함수
  3. 컴포넌트들의 state들을 전부 최신화 시켜주는 함수
  4. 액션객체를 추가하기위한 함수
profile
智(지)! 德(덕)! 體(체)!
post-custom-banner

0개의 댓글