在 Redux 中链接多个异步调度
chaining multiple async dispatch in Redux
我正在尝试以下列方式将多个操作链接在一起:
一个。 post 用户数据到数据库
乙。使用 posted 数据查询 Elasticsearch 的结果
(我同时做A和B)
B1。使用 ES 的结果,查询原始数据库以获取两个表的结果
B2.导航到新页面并更新 UI
我现在正在使用 thunk 来推理我的代码,但我也发现这种异步模式非常冗长:
export function fetchRecipes(request) {
return function(dispatch) {
dispatch(requestRecipes(request))
return fetch(url)
.then(response => response.json())
.then(json => dispatch(receiveRecipes(request, json))
)
}
}
this,以及 "requestRecipes" 和 "receiveRecipes" 作为其他动作创建者似乎只是为了进行一次异步调用。 (请求、接收和获取函数)
总结:当你链接 2-3 个输出相互依赖的异步操作时(我需要尽可能地承诺),是否有更有效的方法而不用为每个异步调用编写 3 个函数?
我认为一定有办法。我正在根据 Redux 文档进行模式匹配,很快就对我创建的函数感到不知所措
非常感谢您的反馈!
您可以使用 redux-saga
而不是 redux-thunk
来更轻松地实现此目的。 redux-saga
让您可以使用生成器描述您的工作并且更容易推理。
第一步是描述如何将数据传递给 redux,而不用担心服务或异步内容。
操作数
// actions.js
function createRequestTypes(base) {
return {
REQUEST: base + "_REQUEST",
SUCCESS: base + "_SUCCESS",
FAILURE: base + "_FAILURE",
}
}
// Create lifecycle types on `RECIPES`
export const RECIPES = createRequestTypes("RECIPES")
// Create related actions
export const recipes = {
// Notify the intent to fetch recipes
request: request => ({type: RECIPES.REQUEST, request})
// Send the response
success: response => ({type: RECIPES.SUCCESS, response})
// Send the error
error: error => ({type: RECIPES.FAILURE, error})
}
减速器
// reducer.js
import * as actions from "./actions"
// This reducer handles all recipes
export default (state = [], action) => {
switch (action.type) {
case actions.RECIPES.SUCCESS:
// Replace current state
return [...action.response]
case actions.RECIPES.FAILURE:
// Clear state on error
return []
default:
return state
}
}
服务
我们还需要食谱API。使用 redux-saga
时,声明服务的最简单方法是创建一个(纯)函数,该函数将请求作为参数读取,并且 returns 一个 Promise
.
// api.js
const url = "https://YOUR_ENPOINT";
export function fetchRecipes(request) {
return fetch(url).then(response => response.json())
}
现在我们需要连接动作和服务。这就是 redux-saga
发挥作用的地方。
// saga.js
import {call, fork, put, take} from "redux-saga/effects"
import * as actions from "./actions"
import * as api from "./api"
function* watchFetchRecipes() {
while (true) {
// Wait for `RECIPES.REQUEST` actions and extract the `request` payload
const {request} = yield take(actions.RECIPES.REQUEST)
try {
// Fetch the recipes
const recipes = yield call(api.fetchRecipes(request))
// Send a new action to notify the UI
yield put(actions.fetchRecipes.success(recipes))
} catch (e) {
// Notify the UI that something went wrong
yield put(actions.fetchRecipes.error(e))
}
}
}
function* rootSaga() {
yield [
fork(watchFetchRecipes)
]
}
就是这样!每当组件发送 RECIPES.REQUEST
操作时,saga 将连接并处理异步工作流。
dispatch(recipes.request(req))
redux-saga
的绝妙之处在于您可以在工作流程中轻松链接异步效果和调度操作。
根据您的描述,您真正更新 UI 的唯一时间是在所有这些异步操作 (B1) 结束时。
如果您不使用前面异步调用的结果来更改您的应用程序状态/更新您的 UI,那么进行这些细粒度操作有什么好处?
当然还有 "loading / request started" 和 "finished loading / request stopped" 之类的东西,但在我看来,在你的情况下,你可以在 redux 之外进行链式异步调用(在某种API层)并且只使用一个动作。
此操作调度 "REQUEST_STARTED",然后调用 API 层,该层执行数据库调用和弹性搜索请求等,然后调度 "REQUEST_SUCCESS" 或 "REQUEST_FAILURE",基于根据承诺的结果,这将为您提供更新 UI.
所需的数据
这样一来,redux 中的状态只关心一个副作用,而不是链式调用的实现细节。此外,您的操作变得更加简单,因为它只处理一个异步调用的结果。
我正在尝试以下列方式将多个操作链接在一起:
一个。 post 用户数据到数据库
乙。使用 posted 数据查询 Elasticsearch 的结果
(我同时做A和B)
B1。使用 ES 的结果,查询原始数据库以获取两个表的结果 B2.导航到新页面并更新 UI
我现在正在使用 thunk 来推理我的代码,但我也发现这种异步模式非常冗长:
export function fetchRecipes(request) {
return function(dispatch) {
dispatch(requestRecipes(request))
return fetch(url)
.then(response => response.json())
.then(json => dispatch(receiveRecipes(request, json))
)
}
}
this,以及 "requestRecipes" 和 "receiveRecipes" 作为其他动作创建者似乎只是为了进行一次异步调用。 (请求、接收和获取函数)
总结:当你链接 2-3 个输出相互依赖的异步操作时(我需要尽可能地承诺),是否有更有效的方法而不用为每个异步调用编写 3 个函数?
我认为一定有办法。我正在根据 Redux 文档进行模式匹配,很快就对我创建的函数感到不知所措
非常感谢您的反馈!
您可以使用 redux-saga
而不是 redux-thunk
来更轻松地实现此目的。 redux-saga
让您可以使用生成器描述您的工作并且更容易推理。
第一步是描述如何将数据传递给 redux,而不用担心服务或异步内容。
操作数
// actions.js
function createRequestTypes(base) {
return {
REQUEST: base + "_REQUEST",
SUCCESS: base + "_SUCCESS",
FAILURE: base + "_FAILURE",
}
}
// Create lifecycle types on `RECIPES`
export const RECIPES = createRequestTypes("RECIPES")
// Create related actions
export const recipes = {
// Notify the intent to fetch recipes
request: request => ({type: RECIPES.REQUEST, request})
// Send the response
success: response => ({type: RECIPES.SUCCESS, response})
// Send the error
error: error => ({type: RECIPES.FAILURE, error})
}
减速器
// reducer.js
import * as actions from "./actions"
// This reducer handles all recipes
export default (state = [], action) => {
switch (action.type) {
case actions.RECIPES.SUCCESS:
// Replace current state
return [...action.response]
case actions.RECIPES.FAILURE:
// Clear state on error
return []
default:
return state
}
}
服务
我们还需要食谱API。使用 redux-saga
时,声明服务的最简单方法是创建一个(纯)函数,该函数将请求作为参数读取,并且 returns 一个 Promise
.
// api.js
const url = "https://YOUR_ENPOINT";
export function fetchRecipes(request) {
return fetch(url).then(response => response.json())
}
现在我们需要连接动作和服务。这就是 redux-saga
发挥作用的地方。
// saga.js
import {call, fork, put, take} from "redux-saga/effects"
import * as actions from "./actions"
import * as api from "./api"
function* watchFetchRecipes() {
while (true) {
// Wait for `RECIPES.REQUEST` actions and extract the `request` payload
const {request} = yield take(actions.RECIPES.REQUEST)
try {
// Fetch the recipes
const recipes = yield call(api.fetchRecipes(request))
// Send a new action to notify the UI
yield put(actions.fetchRecipes.success(recipes))
} catch (e) {
// Notify the UI that something went wrong
yield put(actions.fetchRecipes.error(e))
}
}
}
function* rootSaga() {
yield [
fork(watchFetchRecipes)
]
}
就是这样!每当组件发送 RECIPES.REQUEST
操作时,saga 将连接并处理异步工作流。
dispatch(recipes.request(req))
redux-saga
的绝妙之处在于您可以在工作流程中轻松链接异步效果和调度操作。
根据您的描述,您真正更新 UI 的唯一时间是在所有这些异步操作 (B1) 结束时。
如果您不使用前面异步调用的结果来更改您的应用程序状态/更新您的 UI,那么进行这些细粒度操作有什么好处?
当然还有 "loading / request started" 和 "finished loading / request stopped" 之类的东西,但在我看来,在你的情况下,你可以在 redux 之外进行链式异步调用(在某种API层)并且只使用一个动作。 此操作调度 "REQUEST_STARTED",然后调用 API 层,该层执行数据库调用和弹性搜索请求等,然后调度 "REQUEST_SUCCESS" 或 "REQUEST_FAILURE",基于根据承诺的结果,这将为您提供更新 UI.
所需的数据这样一来,redux 中的状态只关心一个副作用,而不是链式调用的实现细节。此外,您的操作变得更加简单,因为它只处理一个异步调用的结果。