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。

更多资料

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容