当前位置: 首页 > news >正文

redux connect 原理解析 传入的mapstate 和mapdispatch connect()第一次执行后返回一个函数 这个函数接收到的参数是一个组件 对组件进行加工返回

redux connect 原理解析 传入的mapstate 和mapdispatch  connect()第一次执行后返回一个函数 这个函数接收到的参数是一个组件 对组件进行加工返回

高姐阶件调用

mapstatetoProps的调用在connect 函数内订阅执行   createStore的过程 对应 react hooks中 useReducer的过程

const mapStateToProps = (state) => {
    return {
        themeColor:state.themeColor
    };
}

Content = connect(mapStateToProps)(Content);

下面是详细内容

一、目的

之前写过一篇文章,主要是看 react.js 小书的时候,也思考了一下 redux 这种模式(或者说 flux 这种模式)所解决的问题的痛点。

至少应该知道,他们为什么会产生,以及产生的过程中逐步解决了什么问题。

感兴趣的可以全看看 react.js 小书。

之前的文章主要是在完全不使用 react 的情况下写一个 redux 模式的应用,基本的内容如下链接:

  • http://www.ptbird.cn/redux-by-self.html

有了这个前提,又考虑了如何在 React 组件中使用 redux 模式。

如果直接使用 redux 和 react-redux 这两个库的话,应该都知道下面几个概念:

  • Provider
  • connect
  • createStore
  • mapStateToProps
  • mapDispatchToProps
  • ...

二、前提

1、createStore

实现一个简单的 react-redux ,首先需要有 createStore 的基本逻辑,能够进行观察。

下面的 createStore 就是之前文章中写出来的:

/**
 * createStore
 * - 用来创建 store
 * - 实现了观察者模式
 * - 对 reducer 进行了处理
 * - 默认会首先 dispatch 一次空对象,也就是通过 reducer 生成初始化的数据
 * @param {*} reducer
 */
function createStore(reducer) {
  let state = null; // 初始化 state 是 null
  const listeners = []; // 监听者是空
  const subscribe = (listener) => listeners.push(listener); // 如果有监听者,则将其 push 进数组
  const getState = () => state; // 返回 state
  const dispatch = (action) => {
      // 触发 action 
      state = reducer(state, action); // 使用 reducer 覆盖原来的 state
      listeners.forEach((listener) => listener());// 对所有监听者进行更新操作
  };
  dispatch({});// 默认进行一次初始化state
  return {getState, dispatch, subscribe}; // 返回 store 对象
}

2、reducer

面对业务逻辑还需要一个 reducer,比如我直接用的 react.js 小书中的 themeReducer

/**
 * themeReducer 
 * @param {*} state 
 * @param {*} action 
 */
function themeReducer(state, action) {
  // 默认 color red
  if (!state) {
    return {themeColor: 'red'};
  }
  // 现在只写了一个 action
  switch (action.type) {
    case 'CHANGE_COLOR': 
      return {
        ...state,
        themeColor: action.data
      };
    default:
      return state;
  }
}

三、实现业务逻辑

1、connect 高阶组件

实际上 connect 就是一个高阶组件,它将组件包装之后拿到一个能够在组件中直接获取 context 的 state 的组件:

connect 的实现方案在注释中写的很明显:

connect 的作用很明显,把一个组件进行包装之后,能够直接拿到 store 中的 state,此时,state 是作为
props 下发的,当然,组件本身接收的 props 不会有任何的影响。

只实现了 mapToStateProps 和 mapToDispatchProps ,需要引入 prop-types

/**
 * 高阶组件 connect
 * @param {*} mapStateToProps 
 * @param {*} mapDispatchToProps 
 */
export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {
    class Connect extends Component {
        constructor() {
            super();
            this.state = {
                allProps: {}
            };
        }
        // context 约束必须
        static contextTypes = {
            store: PropTypes.object
        };
        // 组件挂在前需要执行的操作
        componentWillMount() {
            const {store} = this.context; // 从上下文中获取 store 该 store 是从根组件传递过来的
            this._updateProps();// 初始化执行一次 updateProps
            store.subscribe(() => this._updateProps()); // 加入观察者
        }
        // 用于更新 props 
        _updateProps() {
            const {store} = this.context;
            let stateProps = mapStateToProps
                ? mapStateToProps(store.getState(), this.props)
                : {}; // 主要用来进行 store 的 state 的获取
            let dispatchProps = mapDispatchToProps
                ? mapDispatchToProps(store.dispatch, this.props)
                : {} // 用来 dispatch 的时候获取 store 的 dispatch
            // 整合普通的 props 和 从 state 生成的 props 
            // 作为完整的 state 返回,这样在子组件中就能够通过 props 获取内容
            this.setState({
                allProps: { 
                    ...stateProps,
                    ...dispatchProps,
                    ...this.props
                }
            })
        }
        render() {
            return <WrappedComponent {...this.state.allProps}/>
        }
    }
    // 返回高阶组件
    return Connect;
}

四、使用 connect

有了 connect 就能够在组件中去使用:

下面代码和 react-redux 基本上是一样的

const mapStateToProps = (state) => {
    return {
        themeColor:state.themeColor
    };
}

Content = connect(mapStateToProps)(Content);

 

相关文章:

  • Flash Lite 与 J2ME 分析比较
  • react dva 复习subscriptions: setup
  • pm2 pm2 --help 使用指南
  • 驳斥一些不看好Flash的观点
  • eruda . 移动端console输出日志调试工具
  • referer
  • 2006年3GSM全球大会10佳手机
  • H5 postMessage方法 以及监听
  • 浏览器和node某方面执行顺序不一样
  • 大餐还是鸡肋?让我们谈谈Flash Lite
  • gulp中的同步异步问题
  • 小试一把 64 位 Windows 编程
  • 什么是options请求?为什么会有options请求?
  • 网站完全恢复
  • rel=noopener可以提升性能
  • 《深入 React 技术栈》
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 【Amaple教程】5. 插件
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • Angular2开发踩坑系列-生产环境编译
  • CSS中外联样式表代表的含义
  • dva中组件的懒加载
  • Git学习与使用心得(1)—— 初始化
  • gops —— Go 程序诊断分析工具
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • js 实现textarea输入字数提示
  • JS函数式编程 数组部分风格 ES6版
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • PHP CLI应用的调试原理
  • VUE es6技巧写法(持续更新中~~~)
  • vue-cli在webpack的配置文件探究
  • Vue学习第二天
  • Zsh 开发指南(第十四篇 文件读写)
  • 安卓应用性能调试和优化经验分享
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • 一个项目push到多个远程Git仓库
  • 《天龙八部3D》Unity技术方案揭秘
  • ​TypeScript都不会用,也敢说会前端?
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (力扣题库)跳跃游戏II(c++)
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • ..回顾17,展望18
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET HttpWebRequest、WebClient、HttpClient
  • .Net Web项目创建比较不错的参考文章
  • .NET下ASPX编程的几个小问题
  • .Net中wcf服务生成及调用
  • @RequestBody与@ModelAttribute
  • [ C++ ] template 模板进阶 (特化,分离编译)
  • []C/C++读取串口接收到的数据程序