We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
虽然网上能搜到各种关于vuex与redux的源码分析文章,而且有很多写得很详细,但我还是决定按照我的思路写几篇博客,重点将放在整体的工作流程以及vuex与redux的一些对比。
第一篇是关于React-redux(5.0.3)的源码分析笔记,因为重在流程整理,所以其中只截取了部分源码
首先看看通常的用法:
const firstState =(state = {}, action){ switch (action.type) { case 'ACTION_ONE': return { // 返回一个新的state } default: return { // 返回一个默认的state } } } // ...secondState类似 // 合并 const rootReducer = combineReducers({ firstState, secondState }) let store = createStore( rootReducer, // 关于中间件放到第二篇 applyMiddleware(thunk) ); <Provider store={store}> // 放一些自己的组件,如: <MyComponent></MyComponent> </Provider>
store如何生成暂时先跳过,暂时只需要知道它是这样的结构:
store = { dispatch, // 即常用的dispatch函数 subscribe, getState, // 通过它可以获取整个state replaceReducer }
从Provider开始:
Provider
export default class Provider extends Component { // react为实现跨级组件通信提供的api,从这一层往下的子组件都可以通过context.store直接拿到store,类似于一个全局变量 getChildContext() { return { store: this.store, storeSubscription: null } } constructor(props, context) { super(props, context) // this.store来自于props this.store = props.store } render() { return Children.only(this.props.children) } }
Provider的功能就是将store传给子孙组件。下面进入子组件MyComponent:
store
MyComponent
export default class MyComponent extends Component{ // ...省略 render() { // 这里this.props已经包含firstState } } // 这里传入的state是通过store.getState()获取到的值,即整个应用的state function mapStateToProps(state) { // 在这里可以从整个state中提取一些在该组件需要用到的属性,比如这里的firstState const {firstState} = state // 通常需要返回一个对象,对象中的属性将通过下面的connect函数注入到组件的props中, return { firstState } } export default connect(mapStateToProps)(MyComponent)
关于connect我在看文档和使用的时候就挺好奇的,是怎么通过connect就可以把mapStateToProps里返回的对象注入到组件中的?关于这一段的流程我专门写了个最小化Demo打断点调试了一下,得出结果如下:
connect
mapStateToProps
执行connect(mapStateToProps)对应的源码是:
connect(mapStateToProps)
function connect( mapStateToProps, mapDispatchToProps, mergeProps ) { // match函数中对mapStateToProps做一些处理, // 定义了mapStateToProps缺失或者mapStateToProps是一个函数时如何处理, // 如果mapStateToProps是一个函数,将对它进行一个包装,返回 // function initProxySelector(dispatch, { displayName }) {...} // 即initMapStateToProps指向function initProxySelector(dispatch, { displayName }) {...} // 至于为什么这么做我还没搞懂 const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps') const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps') const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps') // 这里返回connectHOC()的执行结果,传递了一系列参数包括mapStateToProps, // 这个函数其实就是 /src/components/connectAdvanced.js中的connectAdvanced() // 在这个connectAdvanced里定义了一些contextTypes(猜测是为了从context上获取store) // 然后返回了wrapWithConnect(WrappedComponent){}函数 // 至此connect(mapStateToProps)就执行完了,返回wrapWithConnect(WrappedComponent){}函数 return connectHOC(selectorFactory, { initMapStateToProps, initMapDispatchToProps, initMergeProps, }) }
个人感觉connect(mapStateToProps)就是对mapStateToProps的包装和利用闭包保存一些变量引用还有初始化一些变量。 上面注释中提到connect(mapStateToProps)返回的结果是wrapWithConnect(WrappedComponent){}函数,所以connect(mapStateToProps)(MyComponent)相当于执行wrapWithConnect(MyComponent)。
wrapWithConnect(WrappedComponent){}
connect(mapStateToProps)(MyComponent)
wrapWithConnect(MyComponent)
wrapWithConnect源码:
wrapWithConnect
// 只截取了部分 // 重点关注run方法 function makeSelectorStateful(sourceSelector, store) { // wrap the selector in an object that tracks its results between runs. const selector = { // 下面会多次调用run方法,将在这里比较新旧props,并设置 selector.shouldComponentUpdate run: function runComponentSelector(props) { try { const nextProps = sourceSelector(store.getState(), props) if (nextProps !== selector.props || selector.error) { selector.shouldComponentUpdate = true selector.props = nextProps selector.error = null } } catch (error) { selector.shouldComponentUpdate = true selector.error = error } } } return selector } function wrapWithConnect(WrappedComponent) { // 高阶组件的通常用法,创建一个Connect组件,用来包装我们传入的WrappedComponent class Connect extends Component { constructor(props, context) { super(props, context) // 获取到Provider中的store this.store = props[storeKey] || context[storeKey] this.initSelector() // 初始化Subscription,用于发布订阅模式 this.initSubscription() } componentDidMount() { if (!shouldHandleStateChanges) return // 订阅store,一个发布订阅模式,当store发生变化时调用onStateChange this.subscription.trySubscribe() } componentWillReceiveProps(nextProps) { this.selector.run(nextProps) } shouldComponentUpdate() { // 通过this.selector.shouldComponentUpdate属性避免不必要的更新, // 所以使用了redux之后是不需要自己通过shouldComponentUpdate优化的 return this.selector.shouldComponentUpdate } initSelector() { const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions) this.selector = makeSelectorStateful(sourceSelector, this.store) // 将在run方法中调用mapStateToProps,返回值赋给this.selector.props this.selector.run(this.props) } initSubscription() { if (!shouldHandleStateChanges) return const parentSub = (this.propsMode ? this.props : this.context)[subscriptionKey] this.subscription = new Subscription(this.store, parentSub, this.onStateChange.bind(this)) } // store发生变化时调用 onStateChange() { this.selector.run(this.props) // setState触发react的更新,这里dummyState是一个空对象, // 只是为了触发react的更新机制,在更新机制中会从通过store.getState()获取最新的state this.setState(dummyState) } render() { // 在这里将额外的props(包括dispatch和mapStateToProps返回值)合并到WrappedComponent(即这里的MyComponent组件) return createElement(WrappedComponent, this.addExtraProps(selector.props)) } } return hoistStatics(Connect, WrappedComponent) } }
现在可以做个总结:
mapStateToProps()
props
store.subscribe
onStateChange
探索react-redux的小秘密 Redux入坑进阶-源码解析 解读redux工作原理
The text was updated successfully, but these errors were encountered:
No branches or pull requests
虽然网上能搜到各种关于vuex与redux的源码分析文章,而且有很多写得很详细,但我还是决定按照我的思路写几篇博客,重点将放在整体的工作流程以及vuex与redux的一些对比。
Redux与React-redux工作流程梳理
第一篇是关于React-redux(5.0.3)的源码分析笔记,因为重在流程整理,所以其中只截取了部分源码
首先看看通常的用法:
store如何生成暂时先跳过,暂时只需要知道它是这样的结构:
从
Provider
开始:Provider
的功能就是将store
传给子孙组件。下面进入子组件MyComponent
:关于
connect
我在看文档和使用的时候就挺好奇的,是怎么通过connect
就可以把mapStateToProps
里返回的对象注入到组件中的?关于这一段的流程我专门写了个最小化Demo打断点调试了一下,得出结果如下:执行
connect(mapStateToProps)
对应的源码是:个人感觉
connect(mapStateToProps)
就是对mapStateToProps的包装和利用闭包保存一些变量引用还有初始化一些变量。 上面注释中提到connect(mapStateToProps)
返回的结果是wrapWithConnect(WrappedComponent){}
函数,所以connect(mapStateToProps)(MyComponent)
相当于执行wrapWithConnect(MyComponent)
。wrapWithConnect
源码:现在可以做个总结:
connect
内部调用了我们定义的mapStateToProps()
,返回值将作为props
注入组件connect
中调用store.subscribe
(这个方法在redux中定义,详情可以看第二篇)传入onStateChange
作为回调,使得state变化时能够执行onStateChange
触发DOM更新参考链接
探索react-redux的小秘密
Redux入坑进阶-源码解析
解读redux工作原理
The text was updated successfully, but these errors were encountered: