redux学习理解04

redux-study

Posted by EWL on December 13, 2018

redux的学习实现第四课:将stateChanger改名为reducer,不要问为什么的reducer

优化createStore的内容

上一节我们写的stateChanger是这个样子的:

function stateChanger(state, action) {
  switch (action.type) {
    case 'CHANGE_TITLE':
      return {
        ...state,
        title: {
          ...state.title,
          text: action.text
        }
      };
    case 'CHANGE_TITLE_COLOR':
      return {
        ...state,
        title: {
          ...state.title,
          color: action.color
        }
      };
    case  'CHANGE_CONTENT':
      return {
        ...state,
        content: {
          ...state.content,
          text: action.text
        }
      };
    case 'CHANGE_CONTENT_COLOR':
      return {
        ...state,
        content: {
          ...state.content,
          color: action.color
        }
      };
    default:
      return state
  }
}

其实,我们可以将stateChanger写入stateChanger中,将初始化state的工作直接交给stateChanger,react小书的作者是这么做的:

if(!state) {
    return {
      title: {
        text: '我是标题',
        color: 'red'
      },
      content: {
        text: '我是内容',
        color: 'blue'
      }
    };
  }

将上述代码添加到stateChanger的开头,这样一来,即使我们没有要更新state,也可以通过不输入state的方式,返回初始化的appState,顺便此处已经可以将原来的appState常量注释掉了。

这样我们可以优化 createStore 成一个参数,因为 state 和 stateChanger 合并到一起了。

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

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

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

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

最开始照着代码去敲的时候,我以为上述代码就可以运行了,但是却意外的报错了,于是就开始艰难的排查,最后发现,上述代码中,将state的初始化交给了stateChanger,但是却没有将初始化的state替换出来,这就直接导致,我们第一次调用renderApp函数的时候找不到初始化appState,于是进行修改,如下:

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

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

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

  const dispatch = (action) => {
    state = stateChanger(state, action);
    //每一次在执行完stateChanger之后就将事件队列里的监听事件执行处罚
    listeners.forEach((listener) => listener());
  };
  dispatch({});// 初始化一次,保证getState能够将初始化的state返回

  return { getState, dispatch, subscribe };
}

其中dispatch({})这句代码至关重要,这让我们在调用store.getState()的时候可以直接获得初始化的state。

此时,我们将createStore的参数stateChanger改名为reducer,并且我们会发现reducer其实是个纯函数,我们传入state,就重新复制一份数据,并修改新的数据,原来传入的数据原封不动,如果我们不传入state,就返回一份初始化的state。

react小书中有这么一段话:

reducer 是不允许有副作用的。你不能在里面操作 DOM,也不能发 Ajax 请求,更不能直接修改 state,它要做的仅仅是 —— 初始化和计算新的 state。

所以总结一下,我们之前创建一个redux的套路就是:

// 定一个 reducer
function reducer (state, action) {
  /* 初始化 state 和 switch case */
}

// 生成 store
const store = createStore(reducer)

// 监听数据变化重新渲染页面
store.subscribe(() => renderApp(store.getState()))

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

// 后面可以随意 dispatch 了,页面自动更新
store.dispatch(...)