당연하다 생각했지만 당연하지 않은 것
- 면접 때 다음과 같은 질문을 받았다.
- '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
반응형
'Programming > 4. JavaScript & React' 카테고리의 다른 글
016_pass by value, pass by reference (0) | 2022.04.23 |
---|---|
015_자바스크립트에서의 클린 코드 (변수, 함수 편) ✏️ (0) | 2022.04.04 |
013_자바스크립트의 비동기 처리 종류 + setTimeout() (0) | 2022.03.31 |
012_정적 타입 언어와 동적 타입 언어, 그리고 TypeScript (0) | 2022.03.25 |
011_'절대값이 2^53보다 크거나 같은 숫자 리터럴은 너무 커서 정수로 정확하게 표시할 수 없습니다.' (0) | 2022.03.15 |
댓글