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

강정우·2023년 10월 19일
0

react.js

목록 보기
45/45
post-thumbnail

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
智(지)! 德(덕)! 體(체)!

0개의 댓글