프리온보딩 과제 -  createStore 최소 구현체 만들기

 

공식문서를 참고해서 createStore를 직접 구현하는 과제를 주셨다.

 

GitHub - reduxjs/redux: Predictable state container for JavaScript apps

Predictable state container for JavaScript apps. Contribute to reduxjs/redux development by creating an account on GitHub.

github.com

 

Redux를 썼을 때도 RTK로 사용해서 createStore에 무엇이 전달되어야하는지 공식문서를 참고했다.

 

createStore | Redux

API > createStore: creating a core Redux store

ko.redux.js.org

 

Store | Redux

API > Store: the core Redux store methods

ko.redux.js.org

 

정리해보면 하나의 store를 만들어주는 함수로 상태를 업데이트해주고 다음 상태를 반환해주는 reducer, 초기 값 preloadedState을 매개변수로 받아서 현재 상태를 반환해주는 getState, reducer를 통한 상태 변경을 시키기 위해 action을 전달하는 dispatch, 마지막으로 dispatch가 발생할 때마다 실행시키는 subscribe(listener)로 구성되어 있다.

 

 

redux의 구조 자체를 안다면 더 쉽고 좋은 글들이 많아 사진으로 봐도 충분할 거 같아 단순 링크만 가져왔다

 

Flux and Redux

If you are working closely with developing React applications, probably the words Flux and Redux might not be strange to you. But most of…

medium.com

 

In : preloadedState, reducer

out : getState, dispatch, subscribe

 

라고 정의할 수 있으며 오픈 소스를 참고하여 만들었다.

// createStore 간단하게 구현해보가
// create Store는 리듀서를 인자로받아 store를 리턴하는 함수이다.
// store는 subscribe(), dispatch(), getState()를 메서드로 가진 객체다.

interface Action {
  type: "ADD_TODO";
  text: string;
}

function todoList(state: any = [], action: Action) {
  switch (action.type) {
    case "ADD_TODO":
      return state.concat([action.text]);
    default:
      return state;
  }
}

const createStore = function <S, A>(
  reducer: (state: S, action: A) => S,
  preloadedState: S
) {
  const currentReducer = reducer;
  let currentState = preloadedState as S;
  let currentListeners: VoidFunction[] | null = [];
  let nextListeners = currentListeners;

  const getState = function (): S {
    return currentState;
  };
  //상태를 업데이트 해줘야하고 상태를 업데이트 했다면 subscribe에 있는 함수들을 실행시켜준다
  const dispatch = function (action: A): A {
    currentState = currentReducer(currentState, action);
    const listeners = (currentListeners = nextListeners);
    if (listeners) listeners.forEach((listener) => listener());

    return action;
  };

  const subscribe = function (listener: VoidFunction) {
    // subscribe는 dispatch가 호출될 떄마다 실행되는 함수(정확히는 상태가 변경될때마다 실행됨)
    // unsubscribe라는 함수를 반환하며 호출되는 함수를 지울 때 사용
    nextListeners.push(listener);

    return function unsubscribe() {
      const index = nextListeners.indexOf(listener);
      nextListeners.splice(index, 1);
      currentListeners = null;
    };
  };

  return { getState, dispatch, subscribe };
};

const store = createStore(todoList, []);
console.log(
  store.dispatch(
    store.dispatch({
      type: "ADD_TODO",
      text: "Read the docs",
    })
  )
);
console.log(store.getState());
console.log(store.subscribe(() => {}));

 

타입 부분을 조금 애먹었는데 하나하나 정의해보니 크게 어렵지 않았다. 오픈 소스로 이루어진 프로젝트 자체를 뜯어본적은 처음이었는데 무슨 동작을 하는지만 확인한다면 구조가 워낙 잘 짜여 있어 어렵지 않게 이해할 수 있을거라고 생각한다.

 

그런데 action의 타입을 지정해주는 부분은 아직도 헷갈린다

복사했습니다!