본문 바로가기

JavaScript

[JavaScript] Vanilla JavaScript로 상태 관리 만들기!

상태 관리? 

작은 프로젝트를 만들 때는 state를 정의하고 state를 바탕으로 필요한 컴포넌트를 랜더링 한다. 

하지만 프로젝트의 규모가 커지면 부모 컴포넌트의 state가 필요한 자식 컴포넌트로 가는 

깊이가 깊어질 수 있다. 

 

그렇게 되면 필요없는 컴포넌트마저도 state가 거쳐가기 때문에 

전체적인 코드가 복잡하게 된다.

 

그래서 나온 것이 상태 관리 시스템이다. 

 

전역으로 상태를 관리하고 변화가 감지되면 상태를 가지고 있는 모든 컴포넌트에서 

리 렌더링이 발생하는 방식이다. 

 

만들기! 

가장 일반적인 방법이 Pub-Sub 패턴으로 만드는 방식이 아닐까 싶다. 

 

전반적인 틀을 Store라는 클래스를 만들고 

해당 클래스의 state는 전역으로 관리되기 위해서 싱글톤으로 만들 것이다. 

 

그리고 정의된 state를 각 컴포넌트에서 selector를 통해서 가지고 오고 

가지고 온 state가 변경되면 해당 컴포넌트를 리 렌더링 시키는 방식을 사용할 것이다. 

 

1. 싱글톤으로 만들기

class Store {
  static #instance;
  #state;

  constructor() {
    return this.#singletonInit();
  }

  #singletonInit() {
    if (Store.#instance) {
      return Store.#instance;
    }

    this.#state = {
      checkin: undefined,
      checkout: undefined,
      minPrice: -1,
      maxPrice: Infinity,
      adult: 0,
      kid: 0,
      baby: 0,
    };

    return (Store.#instance = this);
  }
}

export default Store;

우선 싱글톤으로 Store 클래스를 만들었다. 

그리고 Store에서 사용할 state를 미리 지정해주었다. 

 

이제 저 state 친구들을 이용해서 selecter, dispatch 등등을 만들 것이다. 

 

2. Selecter 만들기 

  selector(stateList, render, componenet) {
    const state = {};

    for (const stateType of stateList) {
      const renderList = this.#render.get(stateType);
      renderList.set(componenet, render);

      state[stateType] = this.#state[stateType];
    }

    return state;
  }

selecter는 Store와 구독 객체를 연결해주기 위한 함수이다. 

 

stateList가 Store를 구독한 객체에서 필요한 state를 배열로 넘겨준다. 

그리고 render 는 해당 state가 변경되면 구독한 객체가 원하는 작업을 해주기 위해서 받았고

component는 구독한 객체끼리 구분하기 위해서 사용한다. 

 

그리고 마지막에 필요한 state를 반환해준다. 

 

3. dispatch 만들기

  dispatch(type, value) {
    this.setState({
      [type]: value,
    });

    const renderList = this.#render.get(type);

    for (const [_, render] of renderList) {
      render();
    }
  }
  
   setState(newState) {
    this.#state = { ...this.#state, ...newState };
  }

각 객체에서 state를 변경하기 위해서 필요한 dispatch 함수이다. 

 

상태를 변경할 type과 value를 받아와서 state를 변경해주고 selecter에서 등록한 

render 함수를 실행해준다. 

 

리액트라면 화면이 다시 랜더링 되는 작업이 이루어질 것이다. 

 

4. update 만들기

  update(stateList) {
    const state = {};

    for (const stateType of stateList) {
      state[stateType] = this.#state[stateType];
    }

    return state;
  }

구독한 객체에서 state 값을 업데이트하기 위해서 만들었다. 

 

기본적인 기능은 selecter와 같지만 render 함수를 등록하는 부분이 사라졌다. 

반응형