2021.11.9

13103 단어 TILTIL

Teaful 소스 코드 분석

상태 관리 라이브러리. 구직 활동을 활발하게 진행할때, 여러 기업에서 프레임워크를 사용하지 않고 간단한 어플리케이션을 개발하라는 과제를 받았다. 원래 리액트를 사용하기도 했었고, DOM 을 직접 조작하기 보다, JSX 와 같은 스타일의 코드를 사용해서 다루는 것이 훨씬 깔끔하다고 생각했기 때문에, 유사 JSX 를 만들어서 사용했었다. 다음은 그 결과물.

import $ from './elements.js';

import { useStore } from './store.js';

export default function App() {
  const [state, dispatch] = useStore();

  const { count } = state;

  const handleClickPlus = () => {
    dispatch({ type: 'plus' });
  };

  const handleClickMinus = () => {
    dispatch({ type: 'minus' });
  };

  return (
    $.div({}, [
      $.h1({}, ['Simple Counter']),
      $.p({}, [count]),
      $.p({}, [
        $.button({ onClick: handleClickPlus }, ['plus']),
        $.button({ onClick: handleClickMinus }, ['minus']),
      ]),
    ])
  );
}

GitHub: https://github.com/gringrape/vanilla-js-projects/tree/main/03-functional-component-counter

여기서 맹점이, 상태를 업데이트 할때, 모든 컴포넌트를 인스턴스를 새로 만든다는 것이었다. 리액트의 reconcilation 과정과 비교할 것도 없이, 매우 비효율적인 과정일 수 밖에 없다.


/// store
const initialState = {
  count: 0,
};

const reducer = (state, action) => ({
  plus: () => ({ count: state.count + 1 }),
  minus: () => ({ count: state.count - 1 }),
})[action.type]();

const store = {
  updateView: null,
  state: initialState,
  dispatch(action) {
    this.state = reducer(this.state, action);
    this.updateView();
  },
  initiate({ update }) {
    this.updateView = update;
  },
};

export const useStore = () => [
  store.state,
  store.dispatch.bind(store),
];

export default store;


/// view 업데이트의 정체...
function update() {
  root.innerHTML = ''; // 모두 나가주세요...
  root.appendChild(
    App(),
  );
}

꼭 필요한 위치에서만 돔을 업데이트하도록 하는 로직이 필요하다. 사실 처음에는 조금 다른 모양을 구상했었다.

리액트 엘리먼트는 위와같이 트리 구조(루트, 계층화된 그래프)를 이루고 있기 때문에, 특정 노드의 값을 useState 와 같은 훅에 같이 넘겨준다음에 해당 view 를 kill 하자는 구상을 했다.

어쨌든 하고자 하는 일은 단순하다. 상태를 사용하는 노드 아래를 업데이트 한다. 구독을 하든, 인스턴스 참조를 넘겨주든 하면 된다. teaful 에서는 어떤 방법을 사용했는지 알아보자.

좋은 웹페이지 즐겨찾기