@toast-ui/chart
Version:
TOAST UI Application: Chart
113 lines (112 loc) • 3.73 kB
JavaScript
import { observable, observe, notify, notifyByPath, computed, watch, extend as reactiveExtend, invisibleWork, } from "./reactive";
import { isUndefined, forEach, pickPropertyWithMakeup, deepCopy } from "../helpers/utils";
export default class Store {
constructor(initStoreState) {
this.computed = {};
this.actions = {};
this.initStoreState = deepCopy(initStoreState);
this.setRootState({});
}
setRootState(state) {
observable(state);
this.state = state;
}
setComputed(namePath, fn, holder = this.computed) {
const splited = namePath.split('.');
const key = splited.splice(splited.length - 1, 1)[0];
const target = pickPropertyWithMakeup(holder, splited);
computed(target, key, fn.bind(null, this.state, this.computed));
}
setWatch(namePath, fn) {
return watch(this, namePath, fn);
}
setAction(name, fn) {
this.actions[name] = fn;
}
dispatch(name, payload, isInvisible) {
// observe.setlayout 안에서 setLayout 액션이 실행되니까 여기서 state.layout getter가 실행되고
// state.layout의 옵져버로 observe.setLayout이 등록된다. 여기서 무한루프
// 즉 observe하고 안에서 특정 대상을 쓸때
// extend(state.layout, layouts); 이런식으로 하게되면 layout의 getter실행되어
// layout을 업데이트하려고 만든 observe를 옵저버로 등록해서 무한루프
if (isInvisible) {
invisibleWork(() => {
// console.log('dispatch', name, ...args);
this.actions[name].call(this, this, payload);
// console.log('dispatch end', name);
});
}
else {
this.actions[name].call(this, this, payload);
}
}
observe(fn) {
return observe(fn.bind(this, this.state, this.computed));
}
observable(target) {
return observable(target);
}
notifyByPath(namePath) {
notifyByPath(this, namePath);
}
notify(target, key) {
notify(target, key);
}
setModule(name, param) {
if (!param) {
param = name;
name = param.name;
}
if (param.state) {
const moduleState = typeof param.state === 'function' ? param.state(this.initStoreState) : param.state;
extend(this.state, moduleState);
}
if (param.computed) {
forEach(param.computed, (item, key) => {
this.setComputed(key, item);
});
}
if (param.watch) {
forEach(param.watch, (item, key) => {
this.setWatch(key, item);
});
}
if (param.action) {
forEach(param.action, (item, key) => {
this.setAction(key, item);
});
}
if (param.observe) {
forEach(param.observe, (item) => {
this.observe(item);
});
}
}
setValue(target, key, source) {
extend(target, {
[key]: source,
});
}
}
export function extend(target, source) {
const newItems = {};
for (const k in source) {
if (!source.hasOwnProperty(k)) {
continue;
}
if (!isUndefined(target[k])) {
if (typeof source[k] === 'object' && !Array.isArray(source[k])) {
extend(target[k], source[k]);
}
else {
target[k] = source[k];
}
}
else {
newItems[k] = source[k];
}
}
if (Object.keys(newItems).length) {
reactiveExtend(target, newItems);
}
}