Front End Development Libraries(六)
freeCodeCamp —- Front End Development Libraries
React和Redux
1. React 和 Redux 入门
React 是提供数据的视图库,能以高效、可预测的方式渲染视图。 Redux 是状态管理框架,可用于简化 APP 应用状态的管理。 在 React Redux app 应用中,通常可创建单一的 Redux store 来管理整个应用的状态。 React 组件仅订阅 store 中与其角色相关的数据, 可直接从 React 组件中分发 actions 以触发 store 对象的更新。
React 组件可以在本地管理自己的状态,但是对于复杂的应用来说,它的状态最好是用 Redux 保存在单一位置,有特定本地状态的独立组件例外。 当单个组件可能仅具有特定于其的本地状态时,算是例外。 最后一点是,Redux 没有内置的 React 支持,需要安装 react-redux
包, 通过这个方式把 Redux 的 state
和 dispatch
作为 props
传给组件。
在接下来的挑战中,先要创建一个可输入新文本消息的 React 组件, 添加这些消息到数组里,在视图上显示数组。 这应该是 React 课程中的一个很好的回顾。 接着,创建 Redux store 和 actions 来管理消息数组的状态。 最后,使用 react-redux
连接 Redux store 和组件,从而将本地状态提取到 Redux store 中。
从 DisplayMessages
组件开始。 把构造函数添加到此组件中,使用含两个属性的状态初始化该组件,这两个属性为:input
(设置为空字符串),messages
(设置为空数组)。
1 | class DisplayMessages extends React.Component { |
2. 首先在本地管理状态
首先,在 render()
方法中,让组件渲染 input
、button
、ul
三个元素。 input
元素的改变会触发 handleChange()
方法。 此外,input
元素会渲染组件状态中 input
的值。 点击按钮 button
需触发 submitMessage()
方法。
接着,写出这两种方法。 handleChange()
方法会更新 input
为用户正在输入的内容。 submitMessage()
方法把当前存储在 input
的消息与本地状态的 messages
数组连接起来,并清除 input
的值。
最后,在 ul
中展示 messages
数组,其中每个元素内容需放到 li
元素内。
3. 提取状态逻辑给 Redux
完成 React 组件后,我们需要把在本地 state
执行的逻辑移到 Redux 中, 这是为小规模 React 应用添加 Redux 的第一步。 该应用的唯一功能是把用户的新消息添加到无序列表中。 下面我们用简单的示例来演示 React 和 Redux 之间的配合。
首先,定义 action 的类型 ADD
,将其设置为常量 ADD
。 接着,定义创建 action 的函数addMessage()
,用该函数创建添加消息的 action, 把 message
传给创建 action 的函数并返回包含该消息的 action
接着,创建名为 messageReducer()
的 reducer 方法,为这些消息处理状态。 初始状态应为空数组。 reducer 向状态中的消息数组添加消息,或返回当前状态。 最后,创建 Redux store 并传给 reducer。
1 | // 定义 ADD、addMessage()、messageReducer() 并在这里存储: |
4. 使用 Provider 连接 Redux 和 React
在上一挑战中,创建了 Redux store 和 action,分别用于处理消息数组和添加新消息。 下一步要为 React 提供访问 Redux store 及发起更新所需的 actions。 react-redux
包可帮助我们完成这些任务。
React Redux 提供的 API 有两个关键的功能:Provider
和 connect
。 会在另一个挑战会介绍 connect
。 Provider
是 React Redux 包装 React 应用的 wrapper 组件, 它允许访问整个组件树中的 Redux store
及 dispatch
(分发)方法。 Provider
需要两个 props:Redux store 和 App 应用的子组件。 用于 App 组件的 Provider
可这样定义:
1 | <Provider store={store}> |
此时,编辑器上显示的是过去几个挑战中所有代码, 包括 Redux store、actions、DisplayMessages
组件。 新出现的代码是底部的AppWrapper
组件, 这个顶级组件可用于渲染 ReactRedux
的 Provider
,并把 Redux 的 store 作为 props 传入。 接着,渲染 DisplayMessages
为子组件。 完成这些任务后,会看到 React 组件渲染到页面上。
注意: React Redux 在此可作全局变量,因此可通过点号表示法访问 Provider。 利用这一点,编辑器上的代码把 Provider
设置为常量,便于你在 AppWrapper
渲染方法中使用。
1 | // Redux: |
5. 映射 State 到 Props
Provider
可向 React 组件提供 state
和 dispatch
,但必须确切地指定所需要的 state 和 actions, 以确保每个组件只能访问所需的 state。 完成这个任务,需要创建两个函数:mapStateToProps()
、mapDispatchToProps()
。
在这两个函数中,声明 state 中函数所要访问的部分及需要 dispatch 的创建 action 的函数。 完成这些,我们就可以迎接下一个挑战,学习如何使用 React Redux 的 connect
方法来把函数连接到组件了。
注意: 在幕后,React Redux 用 store.subscribe()
方法来实现 mapStateToProps()
。
创建 mapStateToProps()
函数, 以 state
为参数,然后返回一个对象,该对象把 state 映射到特定属性名上, 这些属性能通过 props
访问组件。 由于此示例把 app 应用的整个状态保存在单一数组中,可把整个状态传给组件。 在返回的对象中创建 messages
属性,并设置为 state
。
6. 映射 Dispatch 到 Props
mapDispatchToProps()
函数可为 React 组件提供特定的创建 action 的函数,以便组件可 dispatch actions,从而更改 Redux store 中的数据。 该函数的结构跟上一挑战中的mapStateToProps()
函数相似, 它返回一个对象,把 dispatch actions 映射到属性名上,该属性名成为props
。 然而,每个属性都返回一个用 action creator 及与 action 相关的所有数据调用 dispatch
的函数,而不是返回 state
的一部分。 可以访问 dispatch
,因为在定义函数时,我们以参数形式把它传入 mapDispatchToProps()
了,这跟 state
传入 mapStateToProps()
是一样的。 在幕后,React Redux 用 Redux 的 store.dispatch()
来管理这些含 mapDispatchToProps()
的dispatches, 这跟它使用 store.subscribe()
来订阅映射到 state
的组件的方式类似。
例如,创建 action 的函数 loginUser()
把 username
作为 action payload, mapDispatchToProps()
返回给创建 action 的函数的对象如下:
1 | { |
编辑器上提供的是创建 action 的函数 addMessage()
。 写出接收 dispatch
为参数的函数 mapDispatchToProps()
,返回一个 dispatch 函数对象, 其属性为 submitNewMessage
。该函数在 dispatch addMessage()
时为新消息提供一个参数。
7. 连接 Redux 和 React
你已经写了mapStateToProps()
、mapDispatchToProps()
两个函数,现在可以用它们来把 state
和 dispatch
映射到 React 组件的 props
了。 React Redux 的 connect
方法可以完成这个任务。 此方法有 mapStateToProps()
、mapDispatchToProps()
两个可选参数, 它们是可选的,原因是你的组件可能仅需要访问 state
但不需要分发任何 actions,反之亦然。
为了使用此方法,需要传入函数参数并在调用时传入组件。 这种语法有些不寻常,如下所示:
1 | connect(mapStateToProps, mapDispatchToProps)(MyComponent) |
注意:如果要省略 connect
方法中的某个参数,则应当用 null
替换这个参数。
代码编辑器具有 mapStateToProps()
和 mapDispatchToProps()
函数,以及一个名为 Presentational
的新 React 组件。 使用 ReactRedux
全局对象中的 connect
方法将此组件连接到 Redux,并立即在 Presentational
组件上调用它。 将结果赋值给名为 ConnectedComponent
的新 const
,表示连接的组件。 就是这样,现在你已经连接到 Redux 了! 尝试将 connect
的参数更改为 null
,并观察测试结果。
1 | const addMessage = (message) => { |
8. 将 Redux 连接到 Messages App
知道如何使用 connect
连接 React 和 Redux 后,我们可以在 React 组件中应用上面学到的内容。
在上一课,连接到 Redux 的组件命名为 Presentational
,这个命名不是任意的, 这样的术语通常是指未直接连接到 Redux 的 React 组件, 它们只负责执行接收 props 的函数来实现 UI 的呈现。 相比之下,容器组件用来连接到 Redux 上。 这些组件通常负责把 actions 分派给 store,且经常给子组件传入 store state 属性。
到目前为止,我们的编辑器上已包含了整个章节的代码, 唯一不同的是,React 组件被重新命名为 Presentational
,即展示层组件。 创建一个新组件,保存在名为 Container
的常量中。 这个常量用 connect
把 Presentational
组件和 Redux 连接起来。 然后,在AppWrapper
中渲染 React Redux 的 Provider
组件, 给 Provider
传入 Redux store
属性并渲染 Container
为子组件。 设置完所有内容后,将再次看到消息应用程序渲染到页面上。
1 | // Redux: |
9. 将局部状态提取到 Redux 中
马上就完成了! 请回顾一下为管理 React messages app 的状态写的 Redux 代码。 现在有了连接好的 Redux,还要从Presentational
组件中提取状态管理到 Redux, 目前,已连接 Redux,但正在 Presentational
组件中本地处理状态。
在 Presentational
组件中,先删除本地 state
中的 messages
属性, 被删的 messages 将由 Redux 管理。 接着,修改 submitMessage()
方法,使该方法从 this.props
那里分发 submitNewMessage()
;从本地 state
中传入当前消息输入作为参数。 因本地状态删除了 messages
属性,所以在调用 this.setState()
时也要删除 messages
属性。 最后,修改 render()
方法,使其所映射的消息是从 props
接收的,而不是 state
完成这些更改后,我们的应用会实现 Redux 管理应用的状态,但它继续运行着相同的功能。 此示例还阐明了组件获得本地 state
的方式,即在自己的 state
中继续跟踪用户本地输入。 由此可见,Redux 为 React 提供了很有用的状态管理框架。 先前,仅使用 React 的本地状态也实现了相同的结果,这在应付简单的应用时通常是可行的。 但是,随着应用变得越来越大,越来越复杂,应用的状态管理也变得非常困难,Redux 就是为解决这样的问题而诞生的。
1 | // Redux: |