본문 바로가기
Programming/4. JavaScript & React

014_Redux, Context API 없이 전역 관리하기 🔥

by @sangseophwang 2022. 4. 1.

당연하다 생각했지만 당연하지 않은 것

- 면접 때 다음과 같은 질문을 받았다.
- 'Redux나 Context API 없이 전역 관리를 하려면 어떻게 해야할까요?'
- 그동안 위 두 방식을 너무나 당연하게 사용했던지라 면접관님의 질문에 당황하긴 했지만, 당시 내 답변은 '전역으로 관리할 state를 Redux의 store 형식으로 따로 만들어 사용하면 되지 않을까요?' 였다.
- 대략 어떻게 해야할 지에 대한 생각은 했지만 이번 기회에 직접 작성해보며 내가 생각한 답변이 실제로 작동하는지 확인해보기로 했다.

원리

- Redux의 Store, Action, Dispatch의 개념을 활용해 훅을 제작한다.
- Store는 Dispatch가 작동할 때마다 값이 바뀐다.
- Dispatch는 작동할 때마다 Store를 작동시킨다.
- Redux에서는 Action이라는 Dispatch를 실행시키는 일종의 스위치가 있지만, 여기서는 인자로 보내서 작동시킨다.
- 다음과 같은 원리에 의해 작성한 코드는 다음과 같다.
// useGlobalState.js

import { useState, useEffect } from "react";

const createStore = (initialStore) => {
  let store = initialStore;
  const listeners = new Set();

  const dispatch = (action) => {
    store = typeof action === "function" ? action(store) : action;
    listeners.forEach((listener) => listener(() => store));
  };

  const useStore = () => {
    const [, listener] = useState();
    useEffect(() => {
      listeners.add(listener);
      return () => {
        listeners.delete(listener);
      };
    }, []);
    return store;
  };

  return [useStore, dispatch];
};

export default createStore;
// App.js

import createStore from "./Hooks/useGlobalState";

function App() {
  const [useStore, dispatch] = createStore(0);

  const Display = () => {
    const count = useStore();
    return <div>{count}</div>;
  };

  const Plus = () => (
    <button onClick={() => dispatch((count) => count + 1)}>+</button>
  );

  const Minus = () => (
    <button onClick={() => dispatch((count) => count - 1)}>-</button>
  );
  return (
    <div className="App">
      <Display />
      <Plus />
      <Minus />
    </div>
  );
}

export default App;

코드 설명

- 먼저 데이터를 저장할 store와 호출을 감지하는 listeners라는 Set을 만든다.

dispatch
- dispatch를 실행하면 인자로 받아온 action이 함수인지 여부에 따라 그에 맞게 store 값을 변경해준다.
- 그리고 listeners 안에 있는 호출 요소인 listener를 실행한다.
- 여기서 listener는 useStore에서 listeners Set 내부에 넣은 setState이다.

useStore
- useStore는 변화를 감지해 store를 반환하는 함수이다.
- const [,listener] = useState(); 에서 첫번째 요소가 없는데, 여기서 setState는 다음과 같은 용도로 사용한다.
                 const listener: React.Dispatch<(prevState:undefined) => undefined>
- 일종의 함수이자 useStore를 실행시킬 수 있는 스위치 역할을 한다.
- dispatch의 요청을 감지한 listener는 useStore를 실행시키고 listeners를 업데이트한 다음 store 값을 반환해준다.

정리하자면 변화를 요청하는 dispatch, 그리고 그 변화 요청을 감지해 변화한 값을 반환하는 useStore로 일종의 전역 관리를 할 수 있게 된다.

정리

- 간단한 예제를 따라 만들어보며 전역 관리 방식에 대해 다시 이해할 수 있게 됐다.
- 이전까지는 그저 Action이라는 스위치에 맞게 Dispatch 함수를 실행하면 Store 값이 바뀐다고만 이해했었다면 이제는 어떤 방식으로 동작하는지에 대해 이해함으로써 좀 더 전역 관리에 대한 개념을 이해할 수 있었다.
- 그동안 당연하게 사용했던 전역 관리 툴이었고, 이 외에도 너무나 당연하게 React의 다양한 라이브러리를 사용해왔다면 이제부터는 그 원리도 함께 학습하면서 어떤 식으로 동작하는지 이해하면서 코드를 작성해야겠다는 생각을 하게 됐다.
- 면접관님의 간단한 질문과 답변을 제대로 하지 못했다는 경험으로 끝날 수도 있었지만 이번 기회를 통해 좋은 습관이 생긴 것 같아 감사의 인사를 표하고 싶다.

 

 

참고

https://stackoverflow.com/questions/63209420/react-global-state-with-no-context-or-redux-downsides
반응형

댓글