Redux和React的组合

简介

到目前为止,我们仅使用了纯 Redux。也就是说,直到现在一切都没有涉及框架或视图库。

概括来说,此前我们使用 createStore()创建了store,向其传递了 reducer 函数。然后我们学会了如何使用 dispatch()getState()subscribe() 将 Redux 关联到 React 应用。你可能注意到了:效果并不理想。我们最终将store向下传递到主组件,以便访问 dispatch()getState()subscribe()。这种方法对小型应用来说是可行的,但无法扩展到更大规模的更多组件。

这并不表明 Redux 不高效;只是没有正确的抽象。到目前为止,我们学习的都是低级别的 Redux 方法,并尝试在 React 中使用这些方法。如果有更好的抽象呢,专门用于结合使用 Redux 和 React?好消息是,确实有这样的抽象,它被称为 react-redux,由 Redux 本身的发明者创建而成。

react-redux 的最大优势是可以从 React 组件内派遣 action 和访问 Redux store。借助 react-redux 的Provider 组件和connect() 方法,所有这一切成为可能。

connect()使你能够指定哪个组件应该从 store 中接收哪些数据,并且Provider使connect()能正常工作。我们深入了解下这两个概念。

Provider

设置

在使用 Provider 之前,我们需要安装它:

npm install --save react-redux

对于通过 ReactDOM 渲染到 DOM 的组件,确保导入 Provider。注意:该组件的文件名称很灵活,但是你可能经常看到命名为app.jsroot.jsindex.js

import { Provider } from 'react-redux';

使用 Provider 组件

Provider 的奥秘在于 React 的 context|(翻译) 功能。以下内容摘自 React 文档:

“在某些情况下,当你在组件树中传递数据时,你希望不用手动地经过每个级别向下传递属性。你可以在 React 中使用强大的 'context' API 直接这么做"

Provider 使 connect() 成为可能的原因是,正如该文档所描述的,Provider 使我们能够“在组件树中传递数据时,不需要手动地经过每个级别向下传递数据”。

Provider 总结

Provider 使 Redux 能够将数据从 store 传递给需要该数据的任何 React 组件。它使用 React 的 context|(翻译) 功能来实现这一点。

但是,需要访问 store 的组件依然需要一种方式来与其连接。我们之前提到了 connect() 函数,该函数利用函数式编程中的一种技巧,叫做 currying (柯里化) 。在查看 connect() 的具体使用情况之前,我们仔细看看 柯里化的工作原理!

柯里化

下面是一个简单的 plate函数,它具有两个参数:vegetablefruit

function plate(vegetables, fruit) {
  return `I ate a plate of ${vegetables} and ${fruit}!`;
}

plate('corn', 'apples');

现在假设因为任何原因,我们想要将水果的上餐时间延迟到某个时间点。一种方式是返回一个函数,它接受的是可以稍后调用的水果。

function plate(vegetables) {
  return function fruitFunc (fruit) {
    return `I ate a plate of ${vegetables} and ${fruit}!`;
  }
}

const fruitFunc = plate('corn');

现在我们可以调用 fruitFunc,向其传入fruit,依然可以通过 closure 访问蔬菜 (corn)。

另一种没有延迟的编写方法是:

function plate(vegetables) {
  return function fruitFunc (fruit) {
    return `I ate a plate of ${vegetables} and ${fruit}!`;
  }
}

const sentence = plate('corn')('apples');

你可能需要花点时间才能理解里面的双重调用,我们分步讲解下。当你调用plate 函数时,它返回 fruitFunc,后者被调用并传递“apples”。这一技巧在函数式编程中会用到,叫做currying(也称为偏函数应用)。

💡 函数调用 💡
如果你不确定应该返回多少个函数,请看看有多少个函数调用!一般规则是返回的函数数量比调用的函数数量少一个。例如,如果看到 3 个函数调用,则需要返回 2 个函数。

柯里化总结

柯里化 是指向需要额外数据的函数提供部分输入的流程。Redux API 使用柯里化的部分是其 connect() 方法。我们来看看!

深入研究

connect()

  • 安装
    你需要从 NPM 中安装 react-redux(如果尚未安装的话)。
npm install --save react-redux

安装后,就可以从 react-redux软件包中获取connect()

import { connect } from 'react-redux';

使用 Connect

connect() 是一种函数,使组件能够获取数据并从 Redux store 进行派遣。它的语法很有意思。充分使用的话,看起来如下所示:

connect(mapStateToProps, mapDispatchToProps)(MyComponent)

提醒下,MyComponent 是接收 store 数据和/或进行派遣的组件。mapStateToProps()是接收当前 store 和当前属性的函数,返回的内容将作为属性传递给MyComponentmapDispatchToProps()使你能够在派遣中封装 action creator。我们来仔细看看每个概念!

mapStateToProps()

mapStateToProps() 使你能够指定你希望将 store中的哪些数据传递给 React 组件。 它需要一个store的状态,一个可选的ownprops参数,并返回一个对象。检查其完整语法:

mapStateToProps(state, [ownProps])
  • 正如 Redux 文档中所描述的:

“如果指定了该参数,新组件将订阅 Redux store 更新。这意味着任何时候 store 被更新了,mapStateToProps 将被调用。mapStateToProps 的结果必须是纯对象,并与组件的属性合并。”

这意味着 mapStateToProps()返回的对象上的属性将当做 prop 传递给组件!

function User ({ name, age }) {}

function mapStateToProps (state, props) {
  return {
    name: state.user.name,
    age: state.user.age,
  }
}

connect(mapStateToProps)(User)

在上述示例中,name 和 age 都将作为 prop 供组件访问。

mapDispatchToProps()

当你连接组件时,该组件将自动被传入 Redux 的 dispatch()方法。也就是说,如果你想派遣某个 action,可以在组件中按以下方式操作:

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { updateName } from './actions'

class User extends Component {
  state = { name: '' }
  handleUpdateUser = () => {
    this.props.dispatch(updateName(this.state.name))
  }
  render () {}
}

connect()(User)

mapDispatchToProps()可以稍微清理上述代码。mapDispatchToProps() 的整个目标是action creator 接触组件之前,让你能够将 dispatch() 绑定到该 action creator代码如下所示:

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { updateName } from './actions'

class User extends Component {
  state = { name: '' }
  handleUpdateUser = () => {
    this.props.boundUpdateName(this.state.name)
  }
  render () {}
}

function mapDispatchToProps (dispatch) {
  return {
    boundUpdateName: (name) => dispatch(updateName(name))
  }
}

connect(null, mapDispatchToProps)(User)

mapDispatchToProps()完全是可选的,我并不觉得它会使一切更整洁,但是有必要了解下。

这是本视频中所做更改的 commit。
这是本视频中所做更改的 commit。

Connect 总结

connect() 将 React 组件连接到 Redux store。mapStateToProps() 使我们能够指定要将 store 中的哪个状态传递给 React 组件。mapDispatchToProps() 使我们能够在 action creator 抵达组件之前,将将 dispatch 绑定到该 action creator。

更多资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容