Redux
by Eduard Dyckman
HTML
<div id="result">
</div>
<button id="reset">
RESET
</button>
<button id="destroy">
DESTROY VIEW
</button>
JavaScript
class Store {
constructor(reducer) {
this._reducer = reducer;
this._state = undefined;
this._listeners = [];
this.dispatch({
type: '@@init'
});
}
getState() {
return this._state;
}
subscribe(cb) {
this._listeners.push(cb);
return () => {
const index = this._listeners.indexOf(cb);
this._listeners.splice(index, 1);
}
}
dispatch(action) {
this._state = this._reducer(this._state, action);
this._notifyListeners();
}
_notifyListeners() {
this._listeners.forEach((listener) => {
listener(this._state);
})
}
}
class View {
constructor(el, store) {
this._el = el;
this._store = store;
this._unsubscribe = store.subscribe(this._prepareRender.bind(this));
this._prepareRender(store.getState());
}
_prepareRender(state) {
this._el.innerHTML = this.render(state);
}
render() {
throw new Error('This method should be overriden');
}
destroy() {
this._el.innerHTML = '';
this._unsubscribe();
}
}
const Types = {
SET_NAME: 'SET_NAME',
RESET_NAME: 'RESET_NAME',
}
const setNameAction = (name) => ({
type: Types.SET_NAME,
payload: name
});
const resetNameAction = () => ({
type: Types.RESET_NAME
});
class UserView extends View {
constructor(el, store) {
super(el, store);
this._onInput = this._onInput.bind(this);
this._el.addEventListener('change', this._onInput);
}
_onInput(event) {
this._store.dispatch(setNameAction(event.target.value));
}
render({
name
}) {
return `
<div>${name}</div>
<input value="${name}">
`;
}
destroy() {
super.destroy();
this._el.removeEventListener('change', this._onInput);
}
}
const reducer = (state, action) => {
switch (action.type) {
case Types.SET_NAME:
return {
...state,
name: action.payload
}
default:
return {
name: 'Eduard',
};
}
}
const store = new Store(reducer);
const...