[ Vanilla JS ] Flux 패턴으로 상태 관리하기 ( feat. store )

bepyan·2022년 2월 6일
2
post-thumbnail

Flux pattern

React에서 사용되는 상태관리 패턴이다. ( Redux, Context API )

핵심은 동작이 단방향으로 흐르다.

image

Action 상태를 변경하는 메소드. ( action key + payload )

Dispatcher action을 store에게 전달하는 역할.

Model(Store) 상태을 관리하는 역할.

View 화면을 렌더링하는 역할.



Store core

export class Store {
  #state = {};
  #listeners = [];
  #reducer;

  /**
   * 액션을 수행하고 새로운 state를 반환한다. dispatch를 통해 원하는 액션을 수행할 수 있다.
   * @param { {} } state
   * @param {{ (state, actionKey: String, payload: {}): {} }} reducer
   */
  constructor(state, reducer) {
    this.#state = state;
    this.#reducer = reducer;
  }

  getState() {
    return { ...this.#state };
  }

  subscribe(func) {
    this.#listeners.push(func);
  }

  publish() {
    this.#listeners.forEach((func) => func());
  }

  /**
   * @param {string} actionKey
   */
  async dispatch(actionKey, { ...payload } = {}) {
    this.#state = await this.#reducer(this.#state, actionKey, { ...payload });
    this.publish();
  }
}

reducer
Store을 생성할 때 정의한다.
해당 Store에서 어떻게 state을 변경할지(액션)를 미리 정하고 이후 dispatch할 때 해당 액션을 수행한다.

async
비동기 action을 할 수 있기 때문에 붙인다.

#
private 변수를 의미하는 것으로 안붙여도 무방하다.

payload
액션을 수행할 메소드의 인자이다. json타입을 사용한다.



Store 활용

/stores/RecentlyViewedStore.js

import { Store } from "../core";

const initState = { recentlyViewedList: [] };

const reducer = (state, actionKey, { text }) => {
  const { recentlyViewedList } = state;

  switch (actionKey) {
    case "ADD_ITEM":
      const newList = [text, ...recentlyViewedList.filter((v) => v !== text)];
      return { ...state, recentlyViewedList: newList };
    default:
      return { ...state };
  }
};

/**
 * @actionKey `ADD_ITEM`
 * @state { recentlyViewedList: string[] }
 */
export const RecentlyViewedStore = new Store(initState, reducer);

/** */ JSDoc으로 타입을 명시해주면 actionKey, state 타입 작성할 때 실수를 줄일 수 있다.


// getState을 통해서 화면을 렌더링한다.
const renderRecentItems = () => {
    const { recentlyViewedList } = RecentlyViewedStore.getState();
    root.innerHTML = recentlyViewedList.join(", ");
};

// Store 상태가 변경되면 리렌더링을 한다.
RecentlyViewedStore.subscribe(renderRecentItems)

// Store 상태 변경하는 action을 호출한다.
RecentlyViewedStore.dispatch("ADD_ITEM", { text: e.target.innerText });


전체 예제코드 보기

profile
쿠키 공장 이전 중 🚛 쿠키 나누는 것을 좋아해요.

0개의 댓글