redux学习理解02

redux-study

Posted by EWL on December 13, 2018

redux的学习实现第二课:抽离store

上一节的学习中,我们把appState和dispatch已经创建完毕。现在将其抽离出来,集中到一个单独的地方,专门用于生产这种state-dispatch对。

创建createStore的代码如下:

// createStore
function createStore(state, stateChanger) {
  const getState = () => state;//初始化/获取state的函数
  const dispatch = (action) => {
    stateChanger(state, action);
  };

  return { getState, dispatch };
}

对于这一段代码,我的理解是:getState不仅是被外部调用createStore的对象用来获取state,同时也起着初始化state的功能,所有需要使用到state的地方,都需要通过createStore(initState, stateChanger).getState()来获取到state,这样单一的获取方式有助于后续debug。

用上述代码重构一下上一节的内容,如下:

let appState = {
  title: {
    text: '我是标题',
    color: 'red'
  },
  content: {
    text: '我是内容',
    color: 'blue'
  }
};

function renderTitle(title) {
  const titleDOM = document.getElementById('title');
  titleDOM.innerHTML = title.text;
  titleDOM.style.color = title.color;
}

function renderContent(content) {
  const contentDOM = document.getElementById('content');
  contentDOM.innerHTML = content.text;
  contentDOM.style.color = content.color;
}

function renderApp(state) {
  renderTitle(state.title);
  renderContent(state.content);
}

// createStore
function createStore(state, stateChanger) {
  const getState = () => state;//初始化/获取state的函数
  const dispatch = (action) => {
    stateChanger(state, action);
  };

  return { getState, dispatch };
}


function stateChanger(state, action) {
  switch (action.type) {
    case 'CHANGE_TITLE':
      state.title.text = action.text;
      break;
    case 'CHANGE_TITLE_COLOR':
      state.title.color = action.color;
      break;
    case  'CHANGE_CONTENT':
      state.content.text = action.text;
      break;
    case 'CHANGE_CONTENT_COLOR':
      state.content.color = action.color;
      break;
    default:
      break
  }
}
const store = createStore(appState, stateChanger);
// 打印未修改时的state
console.log('store.getS before', store.getState());
// 首次渲染页面
renderApp(store.getState());

setTimeout(() => {
  store.dispatch({ type: 'CHANGE_TITLE_COLOR', color: 'pink' });
  store.dispatch({ type: 'CHANGE_CONTENT', text: 'content第二次被修改' });
  // 打印已修改的state
  console.log('store.getS after', store.getState());
  // 修改内容之后再进行二次渲染
  renderApp(store.getState());
}, 2000);

代码差别:

  1. 上一节的dispatch修改为stateChanger, 且参数改为两个,state以及action,不再直接接触appState
  2. 添加的getState方法用于获取state,让代码与appState产生联系的唯一一处地方只有创建createStore的时候

以上代码的不足之处: 我们每一次借助store.dispatch去修改内容之后,都需要手动的调用一次renderApp才能将页面整个刷新,所以我们需要在dispatch修改的时候就去更新页面,该怎么做呢? 此时就用到了观察者模式,新添加的代码如下:

// createStore
function createStore(state, stateChanger) {
  let listeners = [];

  const getState = () => state;//初始化/获取state的函数

  // 订阅事件
  const subscribe = (listener) => {
    listeners.push(listener);
  };

  const dispatch = (action) => {
    stateChanger(state, action);
    //每一次在执行完stateChanger之后就将事件队列里的监听事件执行处罚
    listeners.forEach((listener) => listener());
  };

  return { getState, dispatch, subscribe };
}
const store = createStore(appState, stateChanger);
// 订阅一次renderApp方法
store.subscribe(() => renderApp(store.getState()));

// 首次渲染页面
renderApp(store.getState());

setTimeout(() => {
  store.dispatch({ type: 'CHANGE_TITLE_COLOR', color: 'pink' });
  store.dispatch({ type: 'CHANGE_CONTENT', text: 'content第二次被修改' });
}, 2000);

可以看到上述代码中,setTimeout中已经删除了renderApp调用,在创建store的时候进行渲染函数的订阅就可以在每一次dispatch之后去执行订阅函数。

本节学习的完整代码如下:

let appState = {
  title: {
    text: '我是标题',
    color: 'red'
  },
  content: {
    text: '我是内容',
    color: 'blue'
  }
};

function renderTitle(title) {
  const titleDOM = document.getElementById('title');
  titleDOM.innerHTML = title.text;
  titleDOM.style.color = title.color;
}

function renderContent(content) {
  const contentDOM = document.getElementById('content');
  contentDOM.innerHTML = content.text;
  contentDOM.style.color = content.color;
}

function renderApp(state) {
  renderTitle(state.title);
  renderContent(state.content);
}

// createStore
function createStore(state, stateChanger) {
  let listeners = [];

  const getState = () => state;//初始化/获取state的函数

  // 订阅事件
  const subscribe = (listener) => {
    listeners.push(listener);
  };

  const dispatch = (action) => {
    stateChanger(state, action);
    //每一次在执行完stateChanger之后就将事件队列里的监听事件执行处罚
    listeners.forEach((listener) => listener());
  };

  return { getState, dispatch, subscribe };
}


function stateChanger(state, action) {
  switch (action.type) {
    case 'CHANGE_TITLE':
      state.title.text = action.text;
      break;
    case 'CHANGE_TITLE_COLOR':
      state.title.color = action.color;
      break;
    case  'CHANGE_CONTENT':
      state.content.text = action.text;
      break;
    case 'CHANGE_CONTENT_COLOR':
      state.content.color = action.color;
      break;
    default:
      break
  }
}
const store = createStore(appState, stateChanger);
// 订阅一次renderApp方法
store.subscribe(() => renderApp(store.getState()));

// 首次渲染页面
renderApp(store.getState());

setTimeout(() => {
  store.dispatch({ type: 'CHANGE_TITLE_COLOR', color: 'pink' });
  store.dispatch({ type: 'CHANGE_CONTENT', text: 'content第二次被修改' });
}, 2000);