211011 TIL JavaScript로 직접 만들며 이해하는 Redux

» 2막, TIL (Today I Learned), 스터디, React.js

JavaScript로 직접 만들며 이해하는 Redux

상태관리 라이브러리에 대해서는 항상 무엇을 써야할까 고민이 되었었다.
처음 React를 공부할 때 Redux를 같이 공부했었는데, 공부하다가 좀 더 쉬워보이는 Mobx로 갈아탔었고, 결국엔 Context API에 정착해서 쓰고 있었다. 모든 프로젝트를 할 때 무조건 Context 만들고 시작했었는데, 어느 날 그냥 prop으로 넘겨도 되는거 아닌가? 하는 깨달음을 얻고서 그 뒤론 거의 prop으로 넘겨 쓰곤 했었다.

필요성을 느낄때 공부하는 것이 학습효과가 가장 높은데, 이제 팀원들이 생기고 같은 프로젝트에서 협업하다보니 관심사 분리가 중요하다는 걸 깨달았다. 그래서 요새 상태 관리를 따로 해줘야겠다는 필요성을 느끼고 있던 와중에 대부분의 팀원들이 Redux에 익숙해서, 다시 Redux를 공부하게 되었다.

어떻게 하면 효과적으로 공부할까 고민하다가 직접 만들어보자! 했고, 스터디 팀원 분들도 리덕스를 공부하고 싶다고 하여 약 4주간 같이 공부하였다.

내가 참고했던 블로그 글은 이 글 이다.


상태관리에 필요한 기능

  1. Observer - 값 바라보게(구독) 하는 기능 (observable)
    • get, set 함수로 이루어진 Observable 함수
    • observe 하고 있는 함수를 다시 render 해주는 observe 함수
  2. Store - store를 만들어주는 기능
    • reducer를 인자로 받아 getState 함수와 dispatch 함수를 리턴하는 CreateStore 함수


위의 블로그 글의 코드를 참고해서 쓴 코드

Observer.js

let currentObserver;

export const observe = cb => {
  currentObserver = cb; // render
  cb();
  currentObserver = null;
};

export const observable = obj => {
  Object.keys(obj).forEach(key => {
    let _value = obj[key];
    const observers = new Set();

    Object.defineProperty(obj, key, {
      get() {
        if (currentObserver) observers.add(currentObserver);
        return _value;
      },

      set(value) {
        if (_value === value) return;
        _value = value;
        observers.forEach(cb => cb()); // observers 돌면서 render 다시 해줌
      }
    })
  });

  return obj;
};

Store.js

import { observable } from './observer.js';

export const createStore = (reducer) => {
  const state = observable(reducer()); 
  const frozenState = {};
  Object.keys(state).forEach(key => {
    Object.defineProperty(frozenState, key, {
      get: () => state[key],
    })
  });

  const dispatch = (action) => {
    const newState = reducer(state, action);
    for (const [key, value] of Object.entries(newState)) {
      if (state[key] === null || state[key === undefined]) continue;
      state[key] = value;
    }
  };

  const getState = () => frozenState;

  return { getState, dispatch };
};

다음엔 Recoil을 한번 공부해보고 싶다.