汪微的博客
zane,做一个有思维的开发者

汪微的博客

redux v3.7.2源码解读与学习之 bindActionCreators

2017年12月18日67 browse

redux是什么、有什么作用,解决什么问题,如果你还不知道,请先去这里: redux中文文档

下面的文章适合对redux有一定理解和使用经验的人

项目github地址:https://github.com/wangweianger/redux-source-code-learning

如果你觉得对你有帮助的话记得给我一个star呢


bindActionCreators干的事情太简单了,都不值得用一篇文章来说明,一句话带过的事,不过还是请允许我啰嗦的阐述一下吧。

还是一如既往的先奉上bindActionCreators的源代码:

function bindActionCreator(actionCreator, dispatch) {
    return (...args) => dispatch(actionCreator(...args))
}
export default function bindActionCreators(actionCreators, dispatch) {
    if (typeof actionCreators === 'function') {
        return bindActionCreator(actionCreators, dispatch)
    }

    if (typeof actionCreators !== 'object' || actionCreators === null) {
        throw new Error(
            `bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` +
            `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
        )
    }
    const keys = Object.keys(actionCreators)
    const boundActionCreators = {}
    for (let i = 0; i < keys.length; i++) {
        const key = keys[i]
        const actionCreator = actionCreators[key]
        if (typeof actionCreator === 'function') {
            boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
        }
    }
    return boundActionCreators
}


问:怎么能这么简洁呢?

答:因为它干的事情很简单啊。

问:那它干了什么事情呢?

答:来吧程序员的世界当然得用代码来说明。


用文字阐述就是:你需要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 Redux store 或 dispatch 传给它。

用代码阐述就是:

let actions = {
    addTodo:...,
    addTodoTwo:...
}
// 父组件
class TodoListContainer extends Component {
    render() {
        // 由 react-redux 注入:
        let { dispatch } = this.props;
        let boundActionCreators = bindActionCreators(actions, dispatch);

        return (
            <childContainer {...boundActionCreators} />
        );
    }
}

// 子组件
class childContainer extends Component {
    componentDidMount(){
        this.props.addTodo();
        this.props.addTodoTwo();
    }
}


子组件中不需要知道dispatch || redux 的存在,却可以调用addTodo和addTodoTwo方法去更新store的数据。


下面我用测试案例的方式去看源代码:

//测试案例
import { createStore,bindActionCreators } from './redux'

const ADD_TODO = 'ADD_TODO'

function addTodo(text) {
  return {
    type: 'ADD_TODO',
    text:'Add Something one'
  };
}
function addTodoTwo(text) {
  return {
    type: 'ADD_TODO',
    text:'Add Something two'
  };
}

let actions = {
    addTodo:addTodo,
    addTodoTwo:addTodoTwo
}

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([ action.text ])
    default:
      return state
  }
}

let store = createStore(todos, [ 'Use Redux' ])


let boundActionCreators = bindActionCreators(actions, store.dispatch);

//boundActionCreators 传递给子组件调用,子组件不需要引入dispatch 直接调用即可
//子组件直接调用
boundActionCreators.addTodo()
console.log(store.getState())

boundActionCreators.addTodoTwo()
console.log(store.getState())



下面我们来推理源代码运行流程(去掉了检查抛错部分):

function bindActionCreator(actionCreator, dispatch) {
    return (...args) => dispatch(actionCreator(...args))
}

/*此处
   actionCreators= { addTodo:addTodo, addTodoTwo:addTodoTwo }
   dispatch = store.dispatch
*/
export default function bindActionCreators(actionCreators, dispatch) {
    
    //因为actionCreators为Object,因此跳过此条件
    if (typeof actionCreators === 'function') {
        return bindActionCreator(actionCreators, dispatch)
    }

    // keys=[ addTodo, addTodoTwo ]
    const keys = Object.keys(actionCreators)

    // 定义 返回dispatch集合
    const boundActionCreators = {}

    //循环遍历keys
    for (let i = 0; i < keys.length; i++) {
        const key = keys[i]
        const actionCreator = actionCreators[key]
        
        /* actionCreator === 'function' 为true 因此返回
              boundActionCreators['addTodo'] =        (...args) => dispatch(actionCreator(...args)),
              boundActionCreators['addTodoTwo'] =  (...args) => dispatch(actionCreator(...args))           
        */
        if (typeof actionCreator === 'function') {
            boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
        }
    }
    
    /* 最终 
        boundActionCreators={ 
                addTodo:        (...args) => dispatch(actionCreator(...args)),
                addTodoTwo:  (...args) => dispatch(actionCreator(...args))
        }
     */
    return boundActionCreators
}



分析得出:最终得到的boundActionCreators方法再子组件中调用就不需要再提供dispatch了。 你懂了吗?反正我是懂了。


总结:

  • 此次分析比较啰嗦,但却很详细,对不了解redux源码的人会有一定的帮助

  • 对熟悉redux功能的人更能了解所以然,用之,揪其根本

  • 同时对自己也是一次详细了解redux功能的一次锻炼

  • 为实现另外的库打好基础,比如react-redux

  • 然每个人都会犯错误,在理解中我一定有错误的地方,望体谅


既然已经熟悉了redux的实现原理和解决的问题,接下来就应该应用上来,无可争议当前redux最大的使用场景就是react框架,怎么更好的把redux库与其他框架更优美的紧密结合起来,因此react-redux是我们最好的学习库了。接下来就详细的去看看react-redux的源码吧。



博主 zane 发表于 2017-12-18 12:13:42,添加在了 redux 标签下

打赏

您的支持将鼓励我继续努力与分享。

扫码打赏,建议金额1-10元

提醒:打赏金额将直接进此方账号,无法退款,请您谨慎操作。

评论

正在加载验证码......

提交