Files
freeCodeCamp/curriculum/challenges/chinese/03-front-end-development-libraries/redux/use-middleware-to-handle-asynchronous-actions.md
Shaun Hamilton c2a11ad00d feat: add 'back/front end' in curriculum (#42596)
* chore: rename APIs and Microservices to include "Backend" (#42515)

* fix typo

* fix typo

* undo change

* Corrected grammar mistake

Corrected a grammar mistake by removing a comma.

* change APIs and Microservices cert title

* update title

* Change APIs and Microservices certi title

* Update translations.json

* update title

* feat(curriculum): rename apis and microservices cert

* rename folder structure

* rename certificate

* rename learn Markdown

* apis-and-microservices -> back-end-development-and-apis

* update backend meta

* update i18n langs and cypress test

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>

* fix: add development to front-end libraries (#42512)

* fix: added-the-word-Development-to-front-end-libraries

* fix/added-the-word-Development-to-front-end-libraries

* fix/added-word-development-to-front-end-libraries-in-other-related-files

* fix/added-the-word-Development-to-front-end-and-all-related-files

* fix/removed-typos-from-last-commit-in-index.md

* fix/reverted-changes-that-i-made-to-dependecies

* fix/removed xvfg

* fix/reverted changes that i made to package.json

* remove unwanted changes

* front-end-development-libraries changes

* rename backend certSlug and README

* update i18n folder names and keys

* test: add legacy path redirect tests

This uses serve.json from the client-config repo, since we currently use
that in production

* fix: create public dir before moving serve.json

* fix: add missing script

* refactor: collect redirect tests

* test: convert to cy.location for stricter tests

* rename certificate folder to 00-certificates

* change crowdin config to recognise new certificates location

* allow translations to be used

Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>

* add forwards slashes to path redirects

* fix cypress path tests again

* plese cypress

* fix: test different challenge

Okay so I literally have no idea why this one particular challenge
fails in Cypress Firefox ONLY. Tom and I paired and spun a full build
instance and confirmed in Firefox the page loads and redirects as
expected. Changing to another bootstrap challenge passes Cypress firefox
locally. Absolutely boggled by this.

AAAAAAAAAAAAAAA

* fix: separate the test

Okay apparently the test does not work unless we separate it into
a different `it` statement.

>:( >:( >:( >:(

Co-authored-by: Sujal Gupta <55016909+heysujal@users.noreply.github.com>
Co-authored-by: Noor Fakhry <65724923+NoorFakhry@users.noreply.github.com>
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>
2021-08-13 21:57:13 -05:00

171 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: 5a24c314108439a4d4036156
title: 使用中间件处理异步操作
challengeType: 6
forumTopicId: 301451
dashedName: use-middleware-to-handle-asynchronous-actions
---
# --description--
目前为止的挑战都在避免讨论异步操作,但它们是 Web 开发中不可避免的一部分。 在某些时候,需要在 Redux 应用程序中使用异步请求,那么如何处理这些类型的请求? Redux 中间件专为此目的而设计,称为 Redux Thunk 中间件。 这里简要介绍如何在 Redux 中使用它。
如果要使用 Redux Thunk 中间件,请将其作为参数传递给 `Redux.applyMiddleware()`。 然后将此函数作为第二个可选参数提供给 `createStore()` 函数, 看一下编辑器底部的代码。 然后,要创建一个异步的 action需要在 action creator 中返回一个以 `dispatch` 为参数的函数。 在这个函数中,可以 dispatch action 并执行异步请求。
在此示例中,使用 `setTimeout()` 模拟异步请求。 通常在执行异步行为之前 dispatch action以便应用程序状态知道正在请求某些数据例如这个状态可以显示加载图标。 然后,一旦收到数据,就会发送另一个 action该 action 的 data 是请求返回的数据同时也代表 API 操作完成。
请记住,正在将 `dispatch` 作为参数传递给这个特殊的 action creator。 需要 dispatch action 时只需将 action 直接传递给 dispatch中间件就可以处理其余的部分。
# --instructions--
`handleAsync()` 的 action creator 中编写两个 dispatch 事件。 在 `setTimeout()`(模拟 API 调用)之前 dispatch `requestingData()`。 然后在收到模拟数据后dispatch `receivedData()` action传入这些数据。 现在已经知道如何处理 Redux 中的异步操作, 其他所有操作都继续像以前一样。
# --hints--
`requestingData` action creator 应返回类型和值都为 `REQUESTING_DATA` 的对象。
```js
assert(requestingData().type === REQUESTING_DATA);
```
`receivedData` action creator 应返回类型和值都等于 `RECEIVED_DATA` 的对象。
```js
assert(receivedData('data').type === RECEIVED_DATA);
```
`asyncDataReducer` 必须是个函数。
```js
assert(typeof asyncDataReducer === 'function');
```
分发 `requestingData` 后 action creator 应该将 store 中 `state` 的 fetching 值更新为 `true`
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(requestingData());
const reqState = store.getState();
return initialState.fetching === false && reqState.fetching === true;
})()
);
```
如果要 dispatch `handleAsync` 应先 dispatch 数据请求的 action然后在收到请求结果后再 dispatch 接收的数据 action。
```js
assert(
(function () {
const noWhiteSpace = __helpers.removeWhiteSpace(handleAsync.toString());
return (
noWhiteSpace.includes('dispatch(requestingData())') === true &&
noWhiteSpace.includes('dispatch(receivedData(data))') === true
);
})()
);
```
# --seed--
## --seed-contents--
```js
const REQUESTING_DATA = 'REQUESTING_DATA'
const RECEIVED_DATA = 'RECEIVED_DATA'
const requestingData = () => { return {type: REQUESTING_DATA} }
const receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }
const handleAsync = () => {
return function(dispatch) {
// Dispatch request action here
setTimeout(function() {
let data = {
users: ['Jeff', 'William', 'Alice']
}
// Dispatch received data action here
}, 2500);
}
};
const defaultState = {
fetching: false,
users: []
};
const asyncDataReducer = (state = defaultState, action) => {
switch(action.type) {
case REQUESTING_DATA:
return {
fetching: true,
users: []
}
case RECEIVED_DATA:
return {
fetching: false,
users: action.users
}
default:
return state;
}
};
const store = Redux.createStore(
asyncDataReducer,
Redux.applyMiddleware(ReduxThunk.default)
);
```
# --solutions--
```js
const REQUESTING_DATA = 'REQUESTING_DATA'
const RECEIVED_DATA = 'RECEIVED_DATA'
const requestingData = () => { return {type: REQUESTING_DATA} }
const receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }
const handleAsync = () => {
return function(dispatch) {
dispatch(requestingData());
setTimeout(function() {
let data = {
users: ['Jeff', 'William', 'Alice']
}
dispatch(receivedData(data));
}, 2500);
}
};
const defaultState = {
fetching: false,
users: []
};
const asyncDataReducer = (state = defaultState, action) => {
switch(action.type) {
case REQUESTING_DATA:
return {
fetching: true,
users: []
}
case RECEIVED_DATA:
return {
fetching: false,
users: action.users
}
default:
return state;
}
};
const store = Redux.createStore(
asyncDataReducer,
Redux.applyMiddleware(ReduxThunk.default)
);
```