react-redux浅析

357 阅读2分钟
这篇文章主要来看下两个用的最多的函数背后的原理,connect和combineReducers

react-redux的connect函数简化版源码解释

// connect() 是一个往组件注入redux相关属性的函数
// 你可以注入数据和(通过分发action去改变数据的)回调函数
function connect(mapStateToProps, mapDispatchToProps) {
  // 通过这一层闭包,它实现了让我们在最后一步注入组件的能力,这样的设计让大家可以把它当成decorator使用
  return function (WrappedComponent) {
    // 返回一个组件,这个结构即react提过的HOC
    return class extends React.Component {
      render() {
        return (
          <WrappedComponent
            {/* 父组件传入的props  */}
            {...this.props}
            {/* Redux store通过map*函数计算出的props */}
            {...mapStateToProps(store.getState(), this.props)}
            {...mapDispatchToProps(store.dispatch, this.props)}
          />
        )
      }
      
      componentDidMount() {
        // 一旦组件连接上store,它会帮你subscribe,所以你的组件不会错过任何状态更新
        this.unsubscribe = store.subscribe(this.handleChange.bind(this))
      }
      
      componentWillUnmount() {
        // 卸载时帮你注销订阅
        this.unsubscribe()
      }
    
      handleChange() {
        // store更新之后重新绘制
        this.forceUpdate()
      }
    }
  }
}

// 这不是真正源码,而是一个简化版的模型.
// 它跳过了‘store从哪来’的问题 (答案: <Provider> 把它放进了React上下文)
// 也跳过了性能优化的问题 (真正的connect()确保了不会做无意义的重绘).

// connect() 的目的就是让你不必考虑订阅store或性能优化,而是如何得到你想要的状态state

// 使用例子
const ConnectedCounter = connect(
  // 回调函数拿到state返回prop
  state => ({
    value: state.counter,
  }),
  // 回调函数拿到dispatch函数,返回包含dispatch的回调函数
  dispatch => ({
    onIncrement() {
      dispatch({ type: 'INCREMENT' })
    }
  })
)(Counter)


Redux的combineReducers函数

reducers太多的时候,我们可能想把他们按照相关性分开,便于管理,在最后用combineReducers在合在一起就行。看下面没用这个函数的例子

function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}

其实真相已经不言而喻了,最后的todoApp就等价于combineReducers

import { combineReducers } from 'redux'

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp

引用

gist.github.com/gaearon/1d1…

redux.js.org/basics/redu…