redux原理学习与理解

毫无疑问,redux是react和RN开发中必不可少的重要组成,很多人使用它的时候,都是照搬,代码写完了,问他具体原理,鲜有人能够解释清楚....

与我而言,这么多年的学习生涯中,学习一项新技能的时候,必定会追根溯源,搞清楚原理和设计初衷,这样不仅更容易理解学习,而且会使用的更加得心应手,出现问题更容易知道从哪里下手解决问题,所以,大周末早上来重新梳理redux这个知识。为什么是重新?因为其实已经快速的学习过几遍了,但是真正的应用在项目中,或者说看别人已经完成的大型项目的时候,其实还是一脸懵逼,总在心里嘀咕,这套流程是怎么运作的?整个数据是怎么流通的???得到的答案总是❌,说到底还是没有完全搞懂redux这个东西。所以今天来从头开始,一步步深入其内部,深入学习,并且记录下来,供自己随时翻阅。花不多说,开始吧!

 

下面以计数器为例,步步深入理解学习。

原始实现:当没有redux的时候,我们最早期实现大抵是这样的:

import React, { PureComponent } from 'react';

import store from '../store';

import {
  addAction
} from '../store/actionCreators'

export default class Home extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      counter: store.getState().counter
    }
  }

  componentDidMount() {
    this.unsubscribue = store.subscribe(() => {
      this.setState({
        counter: store.getState().counter
      })
    })
  }

  componentWillUnmount() {
    this.unsubscribue();
  }

  render() {
    return (
      <div>
        <h1>Home</h1>
        <h2>当前计数: {this.state.counter}</h2>
        <button onClick={e => this.increment()}>+1</button>
        <button onClick={e => this.addNumber(5)}>+5</button>
      </div>
    )
  }

  increment() {
    store.dispatch(addAction(1));
  }

  addNumber(num) {
    store.dispatch(addAction(num));
  }
}

这个很直观,也很容易理解,就是从零开始,完全手动实现这个需求,这样完全OK,可以实现功能,但是这样会有一个问题,假如我有另一个组件,也要实现类似的功能,怎么办呢?

  1. easy!马上动手,再创建一个组件About,一通操作,完成了,大概是上图中的这个样子,看一下效果会发现,其实很多代码是大同小异的,假如一个大型的项目中,成篇的写这些代码,一方面效率很低,更深层的来说,这样的代码非常不优雅,那么我们抽取一下

抽取公共部分:

分析下来,我们决定将一些公共的代码抽取出来

类似上面这个效果,将公共的部分放在一个connect函数里面,这个connect会把这些抽出来的代码连接到Redux和Component中,我们的connect函数实现是这样的

然后,我们在具体的Component中使用封装好的这个connect函数,使用后的代码会变成这样

import React, { PureComponent } from 'react';

import {connect} from '../utils/connect';
import {
  incAction,
  addAction
} from '../store/actionCreators'

class Home extends PureComponent {
  render() {
    return (
      <div>
        <h1>Home</h1>
        <h2>当前计数: {this.props.counter}</h2>
        <button onClick={e => this.props.increment()}>+1</button>
        <button onClick={e => this.props.addNumber(5)}>+5</button>
      </div>
    )
  }
}

const mapStateToProps = state => ({
  counter: state.counter
})

const mapDispatchToProps = dispatch => ({
  increment() {
    dispatch(incAction());
  },
  addNumber(num) {
    dispatch(addAction(num));
  }
})

export default connect(mapStateToProps, mapDispatchToProps)(Home);

可以看到,这个组件现在变得非常整洁,一些订阅,取消订阅,以及组件的生命周期的方法,全部都不需要了,只需要通过pros获取一些属性来显示即可,然后我们要实现类似的功能,只要定义对应的mapStateToProps和mapDispatchToProps函数即可,无需重复繁琐的代码,简直不要太爽

如此方便的操作,当然要分享出来,供全球的同行使用啊,于是想要进一步抽取,做到通用,现在有个问题是我们的connect函数里面会对store有强依赖,这样显然不行的,总不能让别人使用你的库,然后进到里面修改一下这一行,改成别人的store,这样显然行不通,于是,近一步对这个connect进行抽取后,变成了酱

创建一个StoreContext,进行数据共享

connect函数就变成了这样

import React, { PureComponent } from "react";

//创建一个StoreContext,进行传递数据
import { StoreContext } from './context';

export function connect(mapStateToProps, mapDispachToProp) {
  return function enhanceHOC(WrappedComponent) {
    class EnhanceComponent extends PureComponent {
      constructor(props, context) {
        super(props, context);

        this.state = {
          //通过context全局传递数据,做到store的解耦
          storeState: mapStateToProps(context.getState())
        }
      }

      componentDidMount() {
        this.unsubscribe = this.context.subscribe(() => {
          this.setState({
            storeState: mapStateToProps(this.context.getState())
          })
        })
      }

      componentWillUnmount() {
        this.unsubscribe();
      }

      render() {
        return <WrappedComponent {...this.props}
          {...mapStateToProps(this.context.getState())}
          {...mapDispachToProp(this.context.dispatch)} />
      }
    }

    EnhanceComponent.contextType = StoreContext;

    return EnhanceComponent;
  }
}

然后,我们在入口的地方,进行context的包裹,

解耦完成,现在我们的connect对业务逻辑的store没有任何依赖,是完全独立的一个方法,在我们准备封装自己的第三方库,很遗憾的告诉你,其实已经存在了这样的一个库,而且广为流传,就是著名的 react-redux

这么广为流传,肯定是有特别的原因,我们替换成这个库试一下,

react-redux实现:

入口代码变成酱紫

import React from 'react';
import ReactDOM from 'react-dom';

import store from './store';

// import { StoreContext } from './utils/context';
import { Provider } from 'react-redux';

import App from './App';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

发现唯一的区别就是Provider传参的时候value变成了store,其实进去源码看下来和我的实现是完全一样的,就是这里它更直接一点,参数名就叫store,也是为了更容易和我们自己的store对应。

然后我们在自己的组件里面,只需要把我们自己的connect方法换成react-redux的connect函数,惊奇的发现,其他的完全不需要任何改动,已经完成了对接,这不是巧了吗😝

到这里,肯定很想知道这个库这么多星,里面实现到底是怎么样的?是不是和我们的一样呢?

进去看了一通源码,大量的使用了hooks,这些相关的东西后面再抽空补充吧,但是追根溯源,其实整个设计思想,和我们是完全一致的,只是里面会加入一些性能优化方面的判断。

 

至此,redux基本上完成了整个设计思想的学习和记录!对其实现流程有了更加清晰的认识,后面使用起来更加知其然知其所以然了,更加有底气。

学无止境,在FullStack的路上持续乘风破浪,加油!!!

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值