컴포넌트
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>');