React-redux框架之connect()与Provider组件 用法讲解

react-redux

在react-redux 框架中,给我提供了两个常用的API来配合Redux框架的使用,其实在我们的实际项目开发中,我们完全可以不用react-redux框架,但是如果使用此框架,就如虎添翼了。

我们来简单聊聊这两个常用的API

  • connect()
  • Provider 组件

React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。

UI 组件

UI 组件有以下几个特征。

  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用this.state这个变量)
  • 所有数据都由参数(this.props)提供
  • 不使用任何 Redux 的 API

下面就是一个 UI 组件的例子。

const Title =value => <h1>{value}</h1>;

因为不含有状态,UI 组件又称为"纯组件",即它纯函数一样,纯粹由参数决定它的值。

容器组件

容器组件的特征恰恰相反。

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API

总之,只要记住一句话就可以了:UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。

你可能会问,如果一个组件既有 UI 又有业务逻辑,那怎么办?回答是,将它拆分成下面的结构:外面是一个容器组件,里面包了一个UI 组件。前者负责与外部的通信,将数据传给后者,由后者渲染出视图。

React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成。也就是说,用户负责视觉层,状态管理则是全部交给它。

connect()

React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。

import { connect } from 'react-redux'
const VisibleTodoList = connect()(TodoList); 

上面代码中,TodoList是 UI 组件,VisibleTodoList就是由 React-Redux 通过connect方法自动生成的容器组件。

但是,因为没有定义业务逻辑,上面这个容器组件毫无意义,只是 UI 组件的一个单纯的包装层。为了定义业务逻辑,需要给出下面两方面的信息。

  • 输入逻辑:外部的数据(即state对象)如何转换为 UI 组件的参数
  • 输出逻辑:用户发出的动作如何变为 Action 对象,从 UI 组件传出去。

因此,connect方法的完整 API 如下。

import { connect } from 'react-redux'const VisibleTodoList = connect( mapStateToProps, mapDispatchToProps )(TodoList) 

上面代码中,connect方法接受两个参数:mapStateToProps和mapDispatchToProps。它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。

mapStateToProps()

mapStateToProps是一个函数。它的作用就是像它的名字那样,建立一个从(外部的)state对象到(UI 组件的)props对象的映射关系。

作为函数,mapStateToProps执行后应该返回一个对象,里面的每一个键值对就是一个映射。请看下面的例子。

const mapStateToProps = (state) => {return { todos: getVisibleTodos(state.todos, state.visibilityFilter) } } 

上面代码中,mapStateToProps是一个函数,它接受state作为参数,返回一个对象。这个对象有一个todos属性,代表 UI 组件的同名参数,后面的getVisibleTodos也是一个函数,可以从state算出 todos 的值。

下面就是getVisibleTodos的一个例子,用来算出todos。

const getVisibleTodos = (todos, filter) => {switch (filter) { case 'SHOW_ALL': return todos case 'SHOW_COMPLETED': return todos.filter(t => t.completed) case 'SHOW_ACTIVE': return todos.filter(t => !t.completed) default: throw new Error('Unknown filter: ' + filter) } } 

mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。

mapStateToProps的第一个参数总是state对象,还可以使用第二个参数,代表容器组件的props对象。

// 容器组件的代码
//    <FilterLink filter="SHOW_ALL">
//      All
// </FilterLink> const mapStateToProps = (state, ownProps) => { return { active: ownProps.filter === state.visibilityFilter } } 

使用ownProps作为参数后,如果容器组件的参数发生变化,也会引发 UI 组件重新渲染。

connect方法可以省略mapStateToProps参数,那样的话,UI 组件就不会订阅Store,就是说 Store 的更新不会引起 UI 组件的更新。

mapDispatchToProps()

mapDispatchToProps是connect函数的第二个参数,用来建立 UI 组件的参数到store.dispatch方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。它可以是一个函数,也可以是一个对象。

如果mapDispatchToProps是一个函数,会得到dispatch和ownProps(容器组件的props对象)两个参数。

const mapDispatchToProps = (dispatch,ownProps
) => {return {onClick: () => { dispatch({ type: 'SET_VISIBILITY_FILTER', filter: ownProps.filter }); } }; } 

从上面代码可以看到,mapDispatchToProps作为函数,应该返回一个对象,该对象的每个键值对都是一个映射,定义了 UI 组件的参数怎样发出 Action。

如果mapDispatchToProps是一个对象,它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数,会被当作 Action creator ,返回的 Action 会由 Redux 自动发出。举例来说,上面的mapDispatchToProps写成对象就是下面这样。

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

<Provider> 组件

connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。

一种解决方法是将state对象作为参数,传入容器组件。但是,这样做比较麻烦,尤其是容器组件可能在很深的层级,一级级将state传下去就很麻烦。

React-Redux 提供Provider组件,可以让容器组件拿到state。

import { Provider } from 'react-redux'
import { createStore } from 'redux' import todoApp from './reducers' import App from './components/App' let store = createStore(todoApp); render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ) 

上面代码中,Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了。

它的原理是React组件的context属性,请看源码。

class Provider extends Component { getChildContext() { return { store: this.props.store }; } render() { return this.props.children; } } Provider.childContextTypes = { store: React.PropTypes.object } 

上面代码中,store放在了上下文对象context上面。然后,子组件就可以从context拿到store,代码大致如下。

class VisibleTodoList extends Component { componentDidMount() { const { store } = this.context; this.unsubscribe = store.subscribe(() => this.forceUpdate() ); } render() { const props = this.props; const { store } = this.context; const state = store.getState(); // ... } } VisibleTodoList.contextTypes = { store: React.PropTypes.object } 

React-Redux自动生成的容器组件的代码,就类似上面这样,从而拿到store。

实例:计数器

我们来看一个实例。下面是一个计数器组件,它是一个纯的 UI 组件。

class Counter extends Component { render() { const { value, onIncreaseClick } = this.props return ( <div> <span>{value}</span> <button onClick={onIncreaseClick}>Increase</button> </div> ) } } 

上面代码中,这个 UI 组件有两个参数:value和onIncreaseClick。前者需要从state计算得到,后者需要向外发出 Action。

接着,定义value到state的映射,以及onIncreaseClick到dispatch的映射。

function mapStateToProps(state) { return { value: state.count } } function mapDispatchToProps(dispatch) { return { onIncreaseClick: () => dispatch(increaseAction) } } // Action Creator const increaseAction = { type: 'increase' } 

然后,使用connect方法生成容器组件。

const App = connect(mapStateToProps,mapDispatchToProps
)(Counter)

然后,定义这个组件的 Reducer。

// Reducer
function counter(state = { count: 0 }, action) { const count = state.count switch (action.type) { case 'increase': return { count: count + 1 } default: return state } } 

最后,生成store对象,并使用Provider在根组件外面包一层。

import { loadState, saveState } from './localStorage';const persistedState = loadState(); const store = createStore( todoApp, persistedState ); store.subscribe(throttle(() => { saveState({ todos: store.getState().todos, }) }, 1000)) ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );


作者:光强_上海
链接:https://www.jianshu.com/p/81e9e9eaf8fa
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/a1411305006/p/11242650.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/386302.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我们究竟还要学习哪些Android知识?吐血整理

前言 闲来无事在家偶然翻到了之前整理的文档和面试要做到准备路线&#xff0c;虽然内容有点多&#xff0c;但是技多不压身&#xff0c;多多益善 本部分内容是关于Android进阶的一些知识总结&#xff0c;涉及到的知识点比较杂&#xff0c;不过都 是面试中几乎常问的知识点&…

海明距离

处理 非递减或者非递增 排列 的时候 &#xff0c;可以使用计数排序&#xff0c;将时间 复杂度变为 O&#xff08;N&#xff09;&#xff0c;空间复杂度变为O&#xff08;1&#xff09;。 1 int heightChecker(vector<int>& heights) {2 vector<int> res(10…

我们究竟还要学习哪些Android知识?满满干货指导

咸鱼翻身不断上演 2018年5月份&#xff0c;北京&#xff0c;在所谓的互联网寒冬里&#xff0c;一个普通二本的学生&#xff0c;在小公司工作一年后&#xff0c;跳槽拿到了百度的offer&#xff0c;月薪从9k变为17k&#xff0c;涨薪幅度接近100%。 2018年底&#xff0c;上海&am…

ElasticSearch6.3脚本更新

使用上篇文章创建的索引进行学习&#xff1a;https://www.cnblogs.com/wangymd/p/11200996.html 官方文档&#xff1a;https://www.elastic.co/guide/en/elasticsearch/painless/6.3/painless-examples.html 1、脚本更新指定字段 方式1&#xff1a; POST test_index/test_type…

我们究竟还要学习哪些Android知识?看这一篇就够了!

雪上加霜 本人一名Android程序员&#xff0c;今年29岁了。大厂小厂都呆过&#xff0c;现在在腾讯工作&#xff01;明明工作顺利&#xff0c;家庭和睦儿女成全&#xff0c;但是总是会感觉到&#xff0c;一股无形的压力&#xff0c;推着我走&#xff01;作为一名程序员我最怕的不…

Daily scrum 10.15

今天新的UI到了&#xff0c;展示如下。 Icon&#xff1a; Wallpaper&#xff1a; Lay out&#xff1a; search resutls&#xff1a; 感谢我们的UI support Wenchao Shi的帮助&#xff01; 接下来的一周是bug fix阶段&#xff0c;我们总结了一下目前的bug&#xff0c;整理如下&a…

我在美团Android研发岗工作的那5年,含泪整理面经

这篇文章主要介绍了20道经典Handler题及答案解析&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者面试复习具有一定的参考学习价值&#xff0c;内容过多可以先收藏慢慢观看&#xff0c;需要的朋友们下面随着小编来一起学习学习吧。 另外各位观众老爷觉…

中文编程兴起的可能途径

前文中文编程兴起的必然性虽然阐述了长远的必然性, 但很自然地会有以下疑问: 为何至今没有看到国内大公司的任何从事中文编程的实践?如何以较小代价实践中文编程以及创造推广中文编程语言/工具?此文从个人视野尝试解读和设想. 刚刚意识到问题1的主观原因(客观原因请见中文命名…

我想谈谈关于Android面试那些事,一篇文章帮你解答

开头 通常作为一个Android APP开发者&#xff0c;我们并不关心Android的源代码实现&#xff0c;不过随着Android开发者越来越多&#xff0c;企业在筛选Android程序员时越来越看中一个程序员对于Android底层的理解和思考&#xff0c;这里的底层主要就是Android Framewok中各个组…

给后辈的一点建议,分享PDF高清版

前言 咱们这行似乎每个人都有个常识&#xff1a;程序员做到35岁之后&#xff0c;职业道路就很窄了&#xff0c;但我不信这个邪&#xff0c;我今年37岁&#xff0c;依然活跃在开发一线&#xff0c;并且做到了月入四万&#xff0b;。 偶尔也有人问&#xff0c;你是怎么打破35岁…

2019牛客多校第三场 F.Planting Trees

题目链接 题目链接 题解 题面上面很明显的提示了需要严格\(O(n^3)\)的算法。 先考虑一个过不了的做法&#xff0c;枚举右下角的\((x,y)\)&#xff0c;然后二分矩形面积&#xff0c;枚举其中一边&#xff0c;则复杂度是\(O(n^3 \log n^2)\)的。 考虑另外一个做法&#xff0c;同样…

给后辈的一点建议,面试建议

前言 相信很多同学都会有这样的感受&#xff0c;前三天刚刚复习的知识点&#xff0c;今天问的时候怎么就讲不出个所以然了呢&#xff1f; 本文的目的就是致力于帮助大家尽可能的建立Android知识体系&#xff0c;希望大家会喜欢~ 技术专家VS管理&#xff0c;哪条路更适合你&am…

2019 Multi-University Training Contest 1 - 1001 - Blank - dp

http://acm.hdu.edu.cn/showproblem.php?pid6578 不会做&#xff0c;看题解。 设dp[i][j][k][l]表示4种颜色出现的最后的位置分别是i,j,k,l的方法数&#xff0c;保证i>j>k>l。其实不取号&#xff0c;因为同一个位置不能放两个元素&#xff0c;除了开始的若干个比如dp…

给后辈的一点建议,面试必会

前言 2017年进大学开始接触Android&#xff0c;从刚开始接触就不断地听到Android市场饱和&#xff0c;工作难找等消息。虽然当时也非常迷茫&#xff0c;不过由于第一次深入接触编程语言&#xff0c;再加上自己的一点兴趣&#xff0c;就一直坚持下来了。 到现在要毕业了&#…

vue2+less开发,使用vux-loader,配置全局less变量

https://blog.csdn.net/u012396955/article/details/80184701 const webpackConfig originalConfig; // 原来的 module.exports 代码赋值给变量 webpackConfigmodule.exports vuxLoader.merge(webpackConfig, {options: {},plugins: [{name: vux-ui},{name: less-theme, path…

美团Android开发工程师岗位职能要求,真香

前言 说起程序员人们的第一印象就是工资高、加班凶、话少钱多头发少。再加上现在科技互联网公司太吃香&#xff0c;bat、华为小米等公司程序员加班情况被广泛传播&#xff0c;程序员用生命在敲代码的印象刻在了很多人的心里。 与其它行业一样&#xff0c;凡是有高级和普通&…

最长递增子序列_python_算法与数据结构

周末了&#xff0c;实验室的网速还是不给力啊&#xff0c;不知道doctors都在干啥&#xff0c;&#xff0c;&#xff0c;最近都在做算法作业&#xff0c;昨天晚上看了一部电影《将爱进行到底》&#xff0c;刚打开电影没多久就听到了很熟悉的旋律&#xff0c;让我很是惊讶&#x…

美团Android开发工程师岗位职能要求,高级面试题+解析

前言 不知道大家面试的时候&#xff0c;有没有遇到这种情况&#xff0c;面试工资谈的是10K&#xff0c;最后干着40K的活&#xff01;说着冠冕堂皇&#xff0c;提升大家能力的话&#xff0c;做着死命压榨员工&#xff0c;996成了程序员心里的魔咒&#xff01; 初级安卓开发工程…

美团点评APP在移动网络性能优化的实践,吊打面试官系列!

一. 开发背景 想要成为一名优秀的Android开发&#xff0c;你需要一份完备的知识体系&#xff0c;在这里&#xff0c;让我们一起成长为自己所想的那样。 Android 相关 1. Android 之 SharedPreferences 内部原理浅析 2. Android 源码分析-消息队列和 Looper 3. Android 源码分析…

软件工程团队项目Alpha版本产品介绍

经过完整的用户场景定义、功能设计、开发和测试&#xff0c;耗时一个月&#xff0c;我们软件工程的团队项目“Academic search Conference helper”的alpha版本总算在近日出炉了。下面就来简单介绍一下我们的产品。事实上&#xff0c;“Academic search Conference helper”是“…