TDD a React/Redux TodoList 应用程序指南—第 3 部分

TDD a React/Redux TodoList 应用程序指南—第 3 部分

原文:https://medium.com/hackernoon/a-guide-to-tdd-a-react-redux-todolist-app-part-3-f25c2289c54

第 1 部分—链接

第二部分——链接

第三部分——你现在在这里。

第 4 部分—链接

Redux

我过于简化的解释是;UI 元素调度动作,该动作是仅包含相关信息的对象,该动作被发送到缩减器,缩减器接收应用和动作的当前状态并返回新状态,UI 订阅该状态,并在所述状态改变时有效地更新。

我们正在谈论 Redux ,基于 Flux 架构,这里有一个非常好的解释,如果你还不熟悉的话可以读一下。

submitTodo 操作

我们将使用一个constants文件来确保一致性,消除愚蠢的语法错误,并帮助记录我们的代码:

src/constants/index.js

src/actions/test.js

Line 7因为我们将不止一次地使用一个todoText,我们也可以在describe的范围内将它设置为一个常量。

Line 10 — 14当我们以todoText作为参数调用submitTodo函数时,这是我们期望我们的应用程序调度的动作。这是我们的 Redux reducer为了存储这个 todo 所需的最低限度;一个type让缩减器知道这是哪种动作,一个id让它有一个惟一的标识符,还有 todo 本身的text

Line 16断言。

失败的测试告诉我们要构建什么,所以让我们创建动作:

src/actions/index.js

Line 3创建一个可变变量来保存我们的id

Line 5 — 8一个nextId帮助器方法,它递增id然后返回它。

Line 11 — 17我们的动作将text作为参数,并返回一个将被分派给我们的 reducer 的对象。

仅仅说text,text: text,的简写。

我们的测试应该通过了。

submitTodo 缩减程序

这是我们基于动作存储和返回新状态的地方。首先,我们可以测试它在实例化时返回一个initialState:

src/reducers/test.js

Line 3我们导入reducer本身和它的initialState变量。

Line 7断言当我们在没有状态和空动作的情况下调用reducer时,它会正确地返回我们期望的initialState

让我们通过测试:

src/reducers/index.js

Line 1从该文件中导出一个initialState模块。

Line 3导出reducer,这是一个以state(默认为initialState)和action为参数,简单返回state的函数。当这个归约器返回新的状态时,Redux 将跟踪它,并在将来的归约中使用所述新状态。

Line 5导入该文件时,默认导出reducer

现在让我们测试它能否接收我们的submitTodo动作并返回一个新的正确状态:

src/reducers/test.js

Line 3导入我们的types常量。

Line 7设置一个todoText变量来帮助断言一致性。

Line 15 — 19设置我们希望传递给减速器的动作。

Line 21 — 28设置预期回报state,包含一个数组todos,其中链接了我们全新的 todo。

我们的测试向我们展示了什么是错误的,我们期望返回一个新的状态以及我们已经提交的 todo,但是我们仍然只是得到一个空的initialState对象。所以让我们来解决它:

src/reducers/index.js

Line 1导入types模块给我们我们的constants

Line 3 — 5更改我们的initialState以包含一个todos键,它在实例化时是一个空数组。这将以 todo 对象的数组结束。

Line 7我们已经重构了我们的 reducer,使之成为一个不仅仅返回initialState的函数。

Line 8我们使用标准的switch语句返回基于action.type的新计算状态。

Line 10 — 11在我们的动作类型是“SUBMIT_TODO的情况下,我们返回这个状态的对象表示。

Line 12 — 19这种语法的要旨是;我们希望从返回任何存在的东西开始,然后重写我们想要添加、删除或更改的新东西。

Line 12返回解包状态,即状态的所有内容,包括空的todos数组。

Line 13用这个数组覆盖todos键。

Line 14这个数组包含我们当前状态的todos数组碰巧包含的任何内容,无论是什么都不是还是几十个 todo 对象。

Line 15 — 18现在添加一个新的对象到这个数组,给它一个我们传入的action.idid,给它一个我们传入的action.texttext

因此,我们刚刚返回了一个新的状态表示,它包含现有的状态和我们刚刚提交的新 todo。希望这有意义。

如果没有我们可以处理的action.type存在,我们的减速器的默认返回只是现有的状态。

我们的减速器单元测试现在通过了。所以从技术上来说,我们的代码现在知道如何向状态添加一个 todo,现在我们只需要设置 Redux,并通过我们的App组件将事情连接起来。

布线冗余

首先我们需要安装reduxreact-redux作为依赖项。

npm install --save redux react-redux

reduxReact 完全分离,只是一种管理状态的方式,是我们应用程序的唯一真实来源。

react-redux为我们提供了redux的 React 绑定。

让我们来创建我们的商店:

src/store.js

Line 1redux导入combineReducerscreateStore子模块。

Line 2进口我司减速机,可还原商场新状态。

Line 4 — 6在这一点上是多余的,因为我们只有一个减速器,但随着我们应用程序的扩展,我们将希望减速器具有可管理的责任,并将使用combineReducers将其合并为一个供我们的商店使用。

Line 8我们默认导出我们的商店。简单。

然后:

src/index.js

Line 5react-redux导入Provider模块,它的一个目的是为所有包装的子组件提供存储,在本例中是我们的应用程序及其所有子组件。

React-redux-connect 解释。

Line 7导入我们上面创建的store

Line 10 — 15我们在这里做了两件事;重构我们的代码,使其更加清晰,并将我们的App包装在我们的Provider中,在这里我们传递我们的 reducer 和 redux-store 作为store

在我们的渲染方法中为document元素添加一个 eslint 异常。

最后:

src/App.js

导入connect,这样我们就可以将 redux 的必要部分暴露给我们的应用程序。

导入我们之前创建的actions,这样我们就可以在我们的组件中调度它们。

Line 18顾名思义,我们将在store.js中创建的状态准备给组件使用的属性。

同样,我们正在将应用程序中的可分派操作准备为可在组件中使用的属性。

Line 21 — 25我们已经创建了接受text参数的submitTodo分派事件,如果不为 falsey,它将分派我们的actions.submitTodo函数。

Line 28``connect模块现在完成了任务,它给我们的应用程序提供了与状态交互的两种方式;调度操作和订阅状态。另一种解释是:告诉商店如何改变并读取其状态。这现在成为我们从该文件的默认导出。

Line 3导入PropTypes进行我们的道具验证。

Line 14 — 16验证我们即将传入的submitTodo函数。

Line 7我们的connect已经给了我们访问submitTodo的权限,所以我们只需将它传递给我们的App注意:我们已经将其更改为非默认导出,连接的应用程序是默认的,但我们仍然会在稍后的测试中公开它。

Line 10然后我们将它传递给需要它的AddTodo组件。

最后更新测试:

src/App.test.js

Line 5我们不得不从导入App改为导入{ App },因为我们想在不使用整个连接组件的情况下单独测试这个组件,这需要我们传入一个Providerstore

Line 6引入initialState作为我们应用的状态。

Line 9submitTodo创建一个模拟函数。

Line 11 — 15稍微重构一下,让代码可读性更强,更容易扩展,然后消耗statesubmitTodo

下面对 redux 和 connect 做一个清晰简洁的解释。

您可能还会发现 react-redux API 文档非常有用,并且会惊讶于它是如此的小和简单。

我们还没有显示我们的待办事项,但它们实际上可以通过用户界面输入并存储在状态中。抓取 Chrome React devtools 扩展,输入一个 todo,然后点击提交。

现在去商店看看,看到它出现了:

Storing a todo in state

概述

我们已经学会了如何:

  • 试驾行动的创建。
  • 减速器的试驾创作。
  • 将 Redux 连接到我们的应用程序,这样它就可以调度事件和订阅状态。

下一个

让我们开始充分利用订阅 state 的能力,并开始展示一些待办事项吧!

第 1 部分—链接

第 2 部分—链接

第三部分——你现在在这里。

第 4 部分—链接


本站为非盈利网站,作品由网友提供上传,如无意中有侵犯您的版权,请联系删除