Skip to content

redux入门之reducer #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
sunyongjian opened this issue Dec 11, 2016 · 0 comments
Open

redux入门之reducer #9

sunyongjian opened this issue Dec 11, 2016 · 0 comments
Labels

Comments

@sunyongjian
Copy link
Owner

sunyongjian commented Dec 11, 2016

reducer

  • 为什么叫reducer
    大概是由于reducer函数都能作为数组的reduce方法的参数,所以叫reducer的吧。
  • Array中的reduce
    reduce需要两个参数,一个是回调函数,一个是初始值,没有初始值,会默认把数组第一个当初始值,并从第二个开始

模拟数组的reduce方法

Array.prototype.reduce = function reduce (callback, init) {
  var i = 0;
  if(typeof init === 'undefined') {
    init = this[0];
    i = 1;
  }
  if(typeof callback !== 'function') {
    throw new Error(callback + ' is not function')
  }
  for( ;i< this.length; i++ ) {
    init = callback(init, this[i])
  }
  return init ;
}

reduce的使用

var ary = [1,2,3];
console.log(ary.reduce((initialValue, next) => {
  console.log(initialValue, next);
  return next;
},0))
// 01  12  23  3

写一个简单的reducer

function reducer (initialValue, next) {
  console.log(initialValue, next)
  switch (next) {
    case 1:
      return next;
      break;
    default:
      return initialValue
  }
}
// 这个reducer 判断传入的值next。是1 的话 返回结果是 next 也就是1 ,所以最后结果都是1
console.log(ary.reduce(reducer))
// 12  13  1

reducer在redux中的作用

reducer的作用就是设计state结构,它可以给定state 的初始值,更重要的是告诉store,根据对应的action如何更新state。 通常我们的store需要多个reducer组合,成为我们最后的state tree

注意点

  • 保持reducer 的纯净

通常我们的reducer是纯函数(pure function) 即固定的输入返回固定的输出,没有副作用,没有API请求... 等等,之后我们说为什么这么做。
通常我们在处理业务中,比如请求一个列表的数据并渲染。
举个栗子

const initialState = {
  code: -1,
  data: [],
  isFetching: false
};
//初始化我们的state,也就是没有请求之前,我们根据接口的数据格式做一个模拟

function List(state = initialState, action) {
  switch (action.type) {
// 这里的types 通常是我们保存这种常量的一个对象

    case types.FETCH_LIST_SUCCESS:
      return {...state, data:action.data,isFetching:false};
    case types.FETCHING_LIST:
      return {...state, isFetching: true}
    case types.FETCH_LIST_FAILURE:
      return {...state, isFetching:false};
    default:
      return state
    }
}

我们的reducer函数就是根据请求的状态返回不同的数据,但是数据格式是一定的。Fetching就是 请求过程中,比如我们做一个loading效果可能需要这个。然后type是success就是成功我们返回数据。这些请求都放到actions 中了,actions去处理逻辑,数据API,重组数据。只需要传给reducer函数数据结果就ok了。

为什么要重新返回一个对象。

我们可以看到reducer函数在拿到数据后通过Object.assign 重新返回一个对象,直接state.data 修改,返回state不行吗?

首先 我们默认的初始state是不能直接改变的,我们的reducer函数 在数据failure的时候 return了默认的state,这个initialState 是不应该被修改的。

另外,我们的react组件 会多次接受store传入props,每一次都应该是一个全新的对象引用,而不是同一个引用。比如我们需要比较两次传入的props,利用componentWillReciveProps(nextProps) 比较this.props 跟nextProps,肯定是需要两个对象空间的,不然是同一个对象引用也就没法比较了。

所以redux 中的reducer 函数要求我们必须返回新的对象state

redux文档-reducer

多个reducer组合成我们的state tree

通常我们会引入redux提供的一个函数

import { combineReducers } from 'redux'

其实combineReducers做的事情很简单,顾名思义就是合并多个reducer
比如我们一个项目有多个reducer但是最后需要合并成一个,然后告诉store生成state tree,再注入Provider组件,先不关注Provider的问题。我们看一下combineReducers的简单实现

//首先我们组合得到的reducer仍旧是一个函数
//这个reducer会整合所有的reducer
//然后根据我们定义的状态树的格式返回一个大的state tree
// 根据reducers这个对象的key,取到reducer函数,并传入对应的 state

const combineReducers = function combineReducers (reducers) {
  return (state = {}, action) {
    Object.keys(reducers).reduce((initialState, key) => {
      initialState[key] = reducers[key](state[key], action)
      return initialState
    },{})

  }
}

这个函数返回一个rootReducer,然后createStore接收rootReducer,在createStore内部会调用一次dispatch(init),rootReducer 会执行,所有我们制定的reducrs对象中的key 都会被添加到 一个初始化initialState中,遍历将每个子级state添加到initialState 。init的时候,state[key]是undefined,每个reducer函数有初始值 返回。以后的dispatch ,因为有了state tree,state[key]都可以取到值了。

待续...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant