Skip to content

컴포넌트

html 함수 만들기

js
// interface HTMLOptions {
//   events?: object
//   attrs?: object
// }
//
// type html = (
//   tagName: string,
//   children: string | HTMLElement[],
//   options?: HTMLOptions
// ) => HTMLElement

export const html = (tagName, children, options) => {
  const elem = document.createElement(tagName);
  appendChild(elem, children);
  appendOptions(elem, options);
  return elem;
};

const appendChild = (elem, children) => {
  if (Array.isArray(children)) {
    children.forEach((child) => {
      elem.appendChild(child)
    })
  } else {
    elem.textContent = children
  }
};

const appendOptions = (elem, options) => {
  if (options) {
    const {attrs = {}, events = {}} = options;

    forEach(attrs, ([key, value]) => {
      elem.setAttribute(key, value)
    });
    forEach(events, ([key, fn]) => {
      elem.addEventListener(key, fn)
    });
  }
};

const forEach = (obj, fn) => {
  Object
    .entries(obj)
    .forEach(fn)
};

defineComponent 함수 만들기

js
// type defineComponent = (ast?: AST) => HTMLElement | null
export const defineComponent = (renderFn) => renderFn;

컴포넌트 사용예

js
import {defineComponent} from '../../core/defineComponent.js';
import {html} from '../../core/html.js';

export const ButtonComponent = defineComponent(() => {
  const events = {
    click: () => console.log('onClick')
  };
  const attrs = {
    type: 'button'
  };
  return html('button', '버튼', {events, attrs})
});

스토어

Observer 만들기

js
export const createObserver = () => {
  const map = new Map();

  return {
    notify: createNotify(map),
    observe: createObserve(map)
  };
};

const createNotify = (map) => (key, value) => {
  const fns = map.get(key);
  fns.forEach(fn => fn(value))
};

const createObserve = (map) => (key, fn) => {
  map.has(key) || map.set(key, new Set());

  const observers = map.get(key);
  observers.add(fn);
};

Observer 사용예

js
import {createObserver} from '../core/observer.js';

const observer = createObserver();

observer.observe('a', (data) => console.log('a1', data));
observer.observe('a', (data) => console.log('a2', data));
observer.observe('b', (data) => console.log('b1', data));

observer.notify('a', 'A 응답하라');
observer.notify('b', 'B 응답하라');

// a1 A 응답하라
// a2 A 응답하라
// b1 B 응답하라

Store 만들기

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

export const createStore = ({state, mutation, actions}) => {
  const observer = createObserver();
  const innerState = ref(state);

  const commit = (mutationName, payload) => {
    const oldValue = innerState.value;
    const newValue = mutation[mutationName](oldValue, payload);

    innerState.value = newValue;
    detectMutation(oldValue, newValue);
  };
  const detectMutation = (oldValue, newValue) => {
    Object
      .keys(oldValue)
      .forEach((key) => {
        if (oldValue[key] !== newValue[key]) {
          observer.notify(key, newValue[key])
        }
      });
  };

  const context = {
    commit,
    get state () {
      return innerState.value;
    },
  };

  const dispatch = (actionName, payload) => {
    actions[actionName](context, payload);
  };

  return {
    dispatch,
    observe: observer.observe,
  }
};

const ref = (value) => ({value});

Store 사용예

js
import {createStore} from '../../core/store.js';

export const store = createStore({
  state: {
    presentation: null,
    name: '',
    age: '',
  },
  mutation: {
    mutatePresentation: (state, presentation) => {
      return {...state, presentation}
    },
    mutateName: (state, name) => {
      return {...state, name}
    },
    mutateAge: (state, age) => {
      return {...state, age}
    }
  },
  actions: {
    updatePresentation: (context, payload) => {
      context.commit('mutatePresentation', payload);
    },
    updatePersonInfo: (context, {name, age}) => {
      console.log(context.state);
      context.commit('mutateName', name);
      context.commit('mutateAge', age);
    }
  }
});
js
import {store} from './store/store.js'

store.observe('presentation', (presentation) => {
  console.log(presentation);
});
store.observe('name', (name) => {
  console.log(`My Name is ${name}`);
});
store.observe('age', (age) => {
  console.log(`I'm ${age}`);
});

store.dispatch('updatePersonInfo', {
  name: 'Peter',
  age: 10,
});
store.dispatch('updatePresentation', '<div></div>');