redux-2

by Momo l

HTML

<script src="https://npmcdn.com/redux@latest/dist/redux.min.js"></script>
<div>
  <p>
    Clicked: <span id="value1">0</span> times
    <button name="increment">+</button>
    <button name="decrement">-</button>
  </p>
</div>
<div>
  <p>
    Clicked: <span id="value2">0</span> times
    <button name="increment">+</button>
    <button name="decrement">-</button>
  </p>
</div>

Babel + JSX

function counterReducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

/**
 *  简化版的combineReducers实现
 *  接收一个reducer map
 ×  {
 *    reducerKey: reducer,
 *    reducerKey2: reducer2
 *  }   
 *  返回一个reducer, 返回的reducer的state和参数形状一致
 */
function combineReducers(reducerMap) {
  return function combinedReducer(state = {}, action) {
    let hasChanged = false;
    let nextState = {};
    let finalReducerKeys = Object.keys(reducerMap);
    finalReducerKeys.forEach(key => {
      const reducer =  reducerMap[key];
      nextState[key] = reducer(state[key], action);
      hasChanged = hasChanged || nextState[key] !== state[key];
    });
    return hasChanged ? nextState : state;
  };
}

let rootReducer = combineReducers({
      countOne: counterReducer,
      countTwo: counterReducer
    });

let store = Redux.createStore(rootReducer);
let valueEl = document.getElementById('value1');
let valueE2 = document.getElementById('value2');

function render() {
  valueEl.innerHTML = store.getState().countOne.toString();
  valueE2.innerHTML = store.getState().countTwo.toString();
}

render();

store.subscribe(render);

Array.from(
  document.getElementsByName('increment')
).forEach((ele) => {
  ele.addEventListener('click', () => 
    store.dispatch({
      type: 'INCREMENT',
    })
  );
});

Array.from(
  document.getElementsByName('decrement')
).forEach((ele) => {
  ele.addEventListener('click', () => 
    store.dispatch({
      type: 'DECREMENT',
    })
  );
});