本系列面向没有任何基础的 Redux 初学者,帮助开发者掌握 Redux,最后可以在项目中使用。
翻译自:https://medium.com/@navaneeth.penumarthi/redux-complete-beginners-to-advanced-part-2-4aa15b2f43cd
回顾
本文是:[Redux: 从入门到掌握-Part1](https://www.yuque.com/docs/share/3d3e20f4-52b4-4ace-b992-18bc1a534f6a?# 《Redux: 从入门到掌握-Part1》)的续篇,通过上一篇文章,我们理解了 Redux 各种的概念,而这篇文章,我们将通过编写一个简单的 TO-DO 列表的项目来学会如何使用Redux。
如果你还没有准备好,请移步到 Part 1.
这个项目主要是 Redux 为主,因此不会包括 CSS,读者可以自己引入 CSS 样式或在下面的 Github 仓库发起 PR
现在,我们对 Redux 有初步地了解,通过编写一个简单的应用,可以加深对 Redux 的理解。
应用说明
这里我们将编写一个提供基本功能的 TO-DO 应用,比如:
- 添加一个 Task
- 移除一个 Task
- 标记一个 Task 为完成的状态
在编写代码之前,我们需要梳理一下这个应用的组件关系图,并且理解每一个组件负责的事情。
这个应用很简单,但足以让我们在 React 应用中学会使用 Redux。
组件说明
- Main:这是一个父组件,会包括整个应用的所有组件。
- Form:负责添加新的 Task。
- Tasks:这个组件会显示 Tasks,同时会包含移除或标记 Task 的功能。
开始
首先,需要创建一个新的 React 应用,并且安装所有的的依赖。
创建新的 React 应用:
1 | npx create-react-app redux-app |
然后需要安装一些应用的依赖:
1 | npm i react-redux redux uuid |
Store 的数据结构
然后,先来确定一下 Store 的数据结构:
准备好数据结构后,就可以进入编写前端代码了。
前端组件相关
这里开始编写前端部分的代码。
App.js
这个文件会包含一个Main组件。
1 | import React from 'react'; |
Main.js
这个是Form.js和Tasks.js组件的父组件。
1 | import React from 'react'; |
Form.js
这个组件会包括表单输入,用来填写用户新的 Task,同时输入框都是受控组件,因此他们的输入变化会跟本地状态绑定。
1 | import React, { useState } from 'react'; |
可能你注意到了,onFormSubmit这个方法目前还没有任何代码,如果用户提交了一个新的 Task,就需要更新 Store 来创建一条新的数据,这个后面会再讲,这里先来看Tasks这个组件。
Task.js
这个组件,可以加载在 Store 中所有的 Tasks 数据,然后将它们显示出来,并且支持添加或删除 Task,或者标记 Task 的状态。
1 | import React from 'react'; |
Action creators
前端组件部分已经完成,现在需要创建 Action,上文我们提到,组件如果要更新状态的话,就需要调用对应的 Action,这里我们创建 3 个 Action,分别对应不同的功能。
- 在 src 目录下,创建一个新的目录,并命名为 actions。
- 在这个 actions 目录下,创建两个文件,分别命名为
types.js和action.js。
types.js
你还记得,我们之前讲到的,type 是每一个 Action 的必要字段,在这个代码文件中,我们列出了所有的 action types,并且导出它们。
1 | export const ADD_TASK = 'ADD_TASK'; |
action.js
这个代码文件包括了所有的 Action,并且它们都返回了一个 Action 对象。
1 | import { ADD_TASK, REMOVE_TASK, FINISH_TASK } from './types'; |
- addTaskAction,这个是在用户需要创建一条包含 Task 信息时派发的 Action,其组成部分是以
ADD_TASK为 type,Task 的标题或描述为 palyload,最后将这条 Action 用于添加新的 Task。
在用户填完表单并确认需要创建 Task 时,在
onSubmit的事件回调中被调用,视图实现是在Form.js这个代码文件中。
removeTaskAction,这个是在用户想要删除 Task 时派发的 Action,其组成部分是以
REMOVE_TASK为 type,待删除 Task 的 id 为 palyload。在用户执行删除按钮操作时被调用,视图实现是在
Tasks.js代码文件中。finishTaskAction,这个是是用户想要标记 Task 的状态为完成时派发的 Action,其组成部分是以
FINISH_TASK为 type,待完成 Task 的 id 为 palyload。
在用户执行勾选完成操作时被调用,视图实现是在
Tasks.js这个代码文件中。
Reducers
- 在 src 中,创建一个新的目录,命名为
reducers。 - 在这个 reducer 目录中,创建一个新的文件,命名为
index.js。
在任何组件中,只要发起一个 Action 对象,Redux 内部就会将这个对象派发给每一个 reducer,相关的 reducer 就会更新状态,比如添加/移除/标记完成操作,在本文的例子中,我们只需要一个 reducer 就够了。
1 | import { combineReducers } from 'redux'; |
- 每一个 reducer 都可以拿到当前的 state 和 action 对象。
- 如果 Action 返回一个对象,Redux 内部会自动派发这个对象以及当前的 state,以参数的形式给到 reducer。
- reducer 通过匹配 actions 的类型,更新对应状态。
- 虽然在本文的应用中,只有一个 reducer,但是如果是复杂的应用,也可以创建多个 reducer,然后在合并起来。
Provider
Action creators 和 reducer 都创建完了,接下里是将它们跟 React 应用进行关联,这部分工作在 react-redux 会提供Provider这个组件,然后对 App 这个组件进行包裹,代码如下:
1 | import React from 'react'; |
这是 Redux 的样板代码,先导入 reducer,然后传给 create store 函数,最后 create store 函数传给 store 参数。
composeEnhancers 也传入到了 store 参数中,这个在浏览器中,可以用来开启 redux developer tools 调试。

Redux developer tools 这个插件可以用来跟踪或调试 Store 的的状态,从应用启动到任意的时间都可以支持。
现在,Action creators 和 reducers 都编写完了,现在需要关联我们的应用,上文提到,有部分事件的回调方法中没有编写代码,现在是时候补上。
useDispatch Hook
这个 hook 可以让任意一个组件,发起一个 Action。比如在Form.js中,当前用户提交表单时,可以在onSubmit这个事件回调中发起addTaskAction这个 action。
1 | import { addTaskAction } from '../actions/action'; |
useDispatch 在 react-redux 中,最容易使用的 hook:
- 从
react-redux中导入 useDispatch hook。 - 导入 action
- 然后 dispatch 带有标题和描述的 addTaskAction。
给读者的任务
现在你理解了如何使用 useDispatch hook 去发起一个 Action,那么你可以也试试用同样的方式,将处理删除任务和标记完成的代码给填补上。
在这两个功能中,你需要调用
removeTaskAction和finishTaskAction这两个 action,同时你需要在 dispatch 函数中传递 id 参数。
或者你可以直接参考 Github 仓库的代码。
useSelector Hook
最后一个工作是,我们需要将 Tasks 的数据从 Store 读取出来,这个部分的实现是在Tasks.js中,然后加载完数据后,将他们显示到视图上面,因此这就需要用useSelector这个 hook 了,代码如下:
1 | import { useSelector } from 'react-redux/es/exports'; |
- useSelector hook 的 state 参数,是用来访问当前 Store 所有的 state 数据。
- 这个 state 数据只能通过派发 Action,然后经过 reducer 进行更新。
- 在 Action 调用之前,state 数据是
initialState对象的数据。 - 在访问 state 数据时,task 这个 key 对应的是导入 taskReducer 时确定的 key,通过这个属性,就可以访问 Task 的整个数据了。
- 在上面的 redux dev tools 的图片中,可以很清晰的看到 state 的数据结构。
Hooks 只能用于函数组件,如果是在 Class 组件中,则需要用 mapStateToProps 来代替 hooks,这篇文章就不再阐述了。
总结
本文中,我们基本介绍了 Redux 的流程,功能和调用方式,不过 redux 确实有很多样板代码,看起来很重复,现在有很多 redux 的生态轮子都是基于 Redux 的,无论用什么轮子,其关键点或流程都是类似的。
感谢阅读!
Links
[Redux: 从入门到掌握-Part1](https://www.yuque.com/docs/share/3d3e20f4-52b4-4ace-b992-18bc1a534f6a?# 《Redux: 从入门到掌握-Part1》)
Github Repo
Live Demo
[本文谢绝转载,谢谢]