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...