React×Redux——react-redux库connect()方法与Provider组件

在写Redux的时候我们就了解了
如果使用Redux的话配合React是最好的
Dan Abramov为此还特意封装了一个react-redux库来提供便利

概念

一旦我们选择使用了这个react-redux库
那么我们的组件概念就要加以区分了
从现在起我们的组件分为展示组件和容器组件两种
(参考了通俗易懂的阮大神博客)

展示组件

展示组件(presentational component)
也叫UI组件、纯组件
特点如下:

  • 负责UI显示
  • 无状态不使用this.state
  • 数据来自this.props
  • 不使用任何redux的API

展示组件其实就是把我们的普通组件的数据与逻辑抽离出来

容器组件

容器组件(container component)
特点如下:

  • 负责管理数据和业务逻辑
  • 带有内部状态
  • 使用redux的API

容器组件是由我们react-redux库的API通过展示组件生成的

关系

从它们的名字也可以猜到,它们是内外关系
容器组件包裹着展示组件

说的再通俗一些
我们原来是将结构和逻辑都装在一个组件中
现在讲这个组件继续拆成负责视图的组件和负责逻辑数据的组件
解耦进一步增强重用性

下面我们来看一下react-redux库的核心
connect()方法与Provider组件

connect

上面也说到了
我么的容器组件是由库API得到的
而这个函数就是connect
connect的意思就是连接展示组件与容器组件的意思
为了加以区分,我用Container表示容器组件,用Component表示展示组件
用法如下

import {connect} from 'react-redux';
const Container = connect()(Component);

结构就是这个样子

<Container>
    <Component/>
</Container>

不过现在我们仅仅是通过展示组件生成了一个容器组件
并且将它们连接了起来
但是容器组件中并没有数据和逻辑
只是一具空壳,毫无意义
所以我们还需要向这个connect函数中传入两个参数
它接收两个值作为参数:

  • mapStateToProps(输入逻辑)
    • 负责将通过state获得的数据映射到展示组件的this.props
  • mapDispatchToProps(输出逻辑)
    • 负责将用户操作转化为Action的功能函数映射到展示组件的this.props

名字就和reducer一样,只是官方的概念性叫法(不过还是蛮形象的)
使用的时候可以自定义名字(不过一定要语义化)

所以完整的用法应该是这样的

const Container = connect( mapStateToProps,mapDispatchToProps )(Component);

但是此时mapStateToProps与mapDispatchToProps我们还没有定义

mapStateToProps

mapStateToProps负责将state的数据映射到展示组件的this.props
它是一个函数,接收参数state对象
如果有必要的话,还可以使用第二个参数:容器组件的props属性
返回一个对象表示state到展示组件props的映射关系

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

此时你会发现这个函数名有多合适

  • 返回对象中的“值”—— state.list
    • 表示我们要将state的list数组传递给内部的展示组件
  • 返回对象中的“键”—— list
    • 表示我们在展示组件中可以通过this.props.list来获取这个数组

但有时,我们不能这么轻松的就通过state的某个属性值获得要传递的数据
这时我们可以自定义一个处理函数返回要传递的数据

const mapStateToProps = (state) => {
    return {
        list: handler(state.list,state.option);
    }
}

比如说这里handler就是我们的处理函数
拿我上一篇文章的toDoList待办事项列表为例
这个handler大概是这样的

const handler = (list,option) => {
    switch(option){
        case "SHOW_ACTION":
            return list.filter(...);
        case "SHOW_CROSSED":
            return list.filter(...);
        ...
        default:
            return list;
    }
}

这个函数我没有写完整,相信大家应该都能看明白
通过判断option我来将list数组进行 “过滤”
函数返回后作为数据返回给展示组件

mapStateToProps会订阅store,state更新后,就会触发展示组件重绘
不过在connect( )函数中,我们可以省略mapStateToProps
如果这么做的话,store更新就不会触发展示组件重绘了

上面也说道了,除了state我们还可以使用容器组件的属性props

const mapStateToProps = (state,ownProps) => {
    return {
        ...
    }
}

如果容器组件的props发生改变的话,同样会触发展示组件重绘

mapDispatchToProps

mapDispatchToProps负责定义发送action的函数映射到展示组件的this.props
与它的兄弟不同,它既可以是函数也可以是对象
作为函数,它会得到store.dispatch作为参数
同样还有一个容器组件的props属性可以使用
返回值我不用说大家也能猜到
就是一个表示映射关系的对象
但是这里表示的是用户如何发出Action(比如触发事件)

const mapDispatchToProps = (state,ownProps) => {
    return {
        onClick: () => {
            dispatch({
                type: 'SET_FILTER',filter: ownProps.filter
            })
        }
    }
}
  • 返回对象中的“值”—— () => {dispatch(...)}
    • 表示我们要传递给内部展示组件的函数(函数功能:dispatch一个action)
  • 返回对象中的“键”—— onClick
    • 表示我们在展示组件中可以通过this.props.onClick来获取这个函数

如果是作为对象的话,就更简单了
上面的写法和下面的等价

const mapDispatchToProps = {
    onClick: (filter) => {
        type: 'SET_FILTER',filter: filter
    }
}

这个对象的值是一个函数,它被认为是一个Action Creator
函数的参数可以填入容器组件的props
返回的Action会由redux自动dispatch

Provider

在完成了Container与Componet的连接
实现了Container的管理数据与业务逻辑之后还没完
还有问题
我们使用了mapStateToProps,它的参数是state
也就是说,他需要传入state
如果我们手动将state对象一层一层的传入容器组件
应用小还好说,大应用深层的组件简直累死了,绝对让你传到怀疑人生

好在,react-redux提供了Provider组件让我们省了不少功夫
我觉得它就相当于我们整体的容器组件
用法就是在我们根组件外部嵌套一层Provider,传入store
(使用全局的store有风险)
这样所以的子组件都可以开心地拿到state了
我们也省心了

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

小实例

上一次介绍Redux的时候介绍了一个简单的计数器
这次我把那个代码拿过来改装一下

import React from 'react';
import {Component} from 'react'
import ReactDom from 'react-dom';
import {createStore,combineReducers} from 'redux';
import {connect,Provider} from 'react-redux';

首先定义单纯用来展示UI的展示组件

class Counter extends Component {
  render(){
    const {value,reduceHandler,addHandler} = this.props;
    return (
      <div>
        <p>{value}</p>
        <button onClick={reduceHandler}>-</button>
        <button onClick={addHandler}>+</button>
      </div>
    )
  }
};

然后定义映射函数,生成容器组件

const mapStateToProps = (state) => {
  return {
    value: state.cnt
  }
}
const mapDispatchToProps = (dispatch) => {
  return {
    reduceHandler: () => {
      dispatch({type: 'REDUCE'});
    },addHandler: () => {
      dispatch({type: 'ADD'});
    }
  }
}
const APP = connect(mapStateToProps,mapDispatchToProps)(Counter);

Reducer稍微改变一下
因为使用了Provider,这个state就一定要是对象

const reducer = (state = {cnt: 0},action) => {
  switch (action.type) {
    case 'ADD':
      return {cnt: state.cnt + 1};
    case 'REDUCE': 
      return {cnt: state.cnt - 1};
    default: 
      return state;
  }
};
const store = createStore(reducer);

渲染函数中的结构外部嵌套Provider并添加store

const render = () => {
  ReactDom.render(
    <Provider store={store}>
      <APP/>
    </Provider>,document.getElementById('root')
  );
};
render();

有了Provider,我们也就不需要store.dispatch(render)
它会帮我们处理
最后的样式依然是那个样子

==主页传送门==

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom