简介
到目前为止,我们仅使用了纯 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.js
、root.js
或 index.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
函数,它具有两个参数:vegetable
和 fruit
。
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 和当前属性的函数,返回的内容将作为属性传递给MyComponent
。mapDispatchToProps()
使你能够在派遣中封装 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。
更多资料
connect() 与 subscribe() 来自 StackOverflow