如何在 redux 中使用 thunk 解决异步链接
How to resolve async chaining using thunk in redux
我试图在 Redux 中使用 thunk 同时发送两个 post,但是当我尝试发送第二个 post 时,我丢失了前一个 [=18] 的用户 ID =].可能有一个关于如何异步链接这些请求的过程,但我还没有找到好的解决方案。 userSelector
似乎应该保持其状态。我也试过这个link:https://blog.jscrambler.com/async-dispatch-chaining-with-redux-thunk。 Promise.all
不推荐,但我也尝试过 dispatch(…).then(() => dipatch())
。任何反馈都很棒!!
import { configureStore, createAsyncThunk, createSlice, unwrapResult } from '@reduxjs/toolkit';
export const postInfo = createAsyncThunk(
'info/postInfo'
async (infoObject: InfoRequest) => {
const response = await axios.post(`${url}/info`, infoObject);
return response.data;
}
);
export const postSales = createAsyncThunk(
'sales/postSales'
async (salesObject: SalesRequest) => {
const response = await axios.post(`${url}/sales`, salesObject);
return response.data;
}
);
...
const postInfoSlice = createSlice<PostState, SliceCaseReducers<PostState>, string>({
name: 'postInfo',
sales: 'postSales',
initialState: {
request: { status: 'idle', error: '' },
},
reducers: {},
extraReducers: (builder) => {
builder.addCase(postInfo.fulfilled, (state, action) => {
state.request.status = 'succeeded';
state.model = action.payload;
}
builder.addCase(postInfo.rejected, (state, action) => {
state.request.status = 'failed';
state.request.error = action.error.message as string;
})
builder.addCase(postSales.fulfilled, (state, action) => {
state.request.status = 'succeeded';
state.model = action.payload;
}
builder.addCase(postSales.rejected, (state, action) => {
state.request.status = 'failed';
state.request.error = action.error.message as string;
})
},
})
...
const store = configureStore({
reducer:
postInfoSlice.reducer
});
export type RootState = ReturnType<typeof store.getState>;
constant user = useSelector((state: RootState) => state.postState.user);
const sendInfoRequest = async () => {
try {
const infoObjRequest: InfoRequest = {
firstName: 'John',
lastName: 'Smith'
};
await dispatch(postInfo(infoObjRequest)).unwrap();
} catch (err) {
console.log('rejected for post /info', err);
}
};
const sendSalesRequest = async () => {
try {
const salesObjRequest: SalesRequest = {
firstName: 'John',
lastName: 'Smith',
userId: user?.id
};
await dispatch(postSales(salesObjRequest)).unwrap();
} catch (err) {
console.log('rejected for post /sales', err);
}
};
// Here is where I am dispatching both post where sendSalesRequest can't get the user id from previous postInfo.
sendInfoRequest();
sendSalesRequest();
为什么不在请求中将 ID 作为变量传递?
//is user null or not initialized?
sendInfoRequest(user?.id);
sendSalesRequest(user?.id);
显式发送内容没有错——尤其是在异步上下文中(也更容易测试)。
我认为更大的问题是你的状态可能不是你所期望的(比如 null)。根据我的经验,让事情尽可能简单明确是最有意义的。
回复评论
我在理解你的问题时遇到一些困难,但如果我理解你基本上想要做的逻辑:
-> Send request -> get ID -> use ID
从根本上说,如果不知道 ID,就无法预先完成。您可能想要的是:
-> Send request (wait)
-> with data do {
action1, action2, etc...
}
没有足够的代码可以为您提供除此之外的任何真实信息。如果用户 ID 在您所在的州不存在,您需要请求并使用它。在 redux 中通常看起来像
//And please forgive me, there are A LOT of different ways to write this
...
const doAfterUserIdExists = (userId) => {
dispatch(a)
dispatch(b)
...
dispatch(x)
}
dispatch( initialAction(doAfterUserIdExists) )
//--in the backend
export const initialAction = (callback) => {
return dispatch => {
//do some business logic
...
const user = new User()//ID is created
if(callback) {
callback(user)
}
dispatch({
type: CASCADE_USER_FUNCTION,
user: user,
})
}
}
这与您正在做的并没有什么不同,只是它具有线性流程。 Promise.all()
也不可行,因为它会同时 运行 您的所有事件(毫无意义,您首先需要一个 ID)。
这不是一个完美的解决方案,但它可以让您了解如何控制数据流。您还可以研究 Sagas 或其他模式以使“thunks”起作用。或者,您可以翻转它,以便发布信息和销售请求等“子逻辑”在 back-end 中发生(如果它们是交易的一部分)。
这并不神奇,您需要找到适合您的解决方案。我倾向于依靠回调,因为它们是线性流程,但有许多不同的模式。我发现这个最容易阅读。
我试图在 Redux 中使用 thunk 同时发送两个 post,但是当我尝试发送第二个 post 时,我丢失了前一个 [=18] 的用户 ID =].可能有一个关于如何异步链接这些请求的过程,但我还没有找到好的解决方案。 userSelector
似乎应该保持其状态。我也试过这个link:https://blog.jscrambler.com/async-dispatch-chaining-with-redux-thunk。 Promise.all
不推荐,但我也尝试过 dispatch(…).then(() => dipatch())
。任何反馈都很棒!!
import { configureStore, createAsyncThunk, createSlice, unwrapResult } from '@reduxjs/toolkit';
export const postInfo = createAsyncThunk(
'info/postInfo'
async (infoObject: InfoRequest) => {
const response = await axios.post(`${url}/info`, infoObject);
return response.data;
}
);
export const postSales = createAsyncThunk(
'sales/postSales'
async (salesObject: SalesRequest) => {
const response = await axios.post(`${url}/sales`, salesObject);
return response.data;
}
);
...
const postInfoSlice = createSlice<PostState, SliceCaseReducers<PostState>, string>({
name: 'postInfo',
sales: 'postSales',
initialState: {
request: { status: 'idle', error: '' },
},
reducers: {},
extraReducers: (builder) => {
builder.addCase(postInfo.fulfilled, (state, action) => {
state.request.status = 'succeeded';
state.model = action.payload;
}
builder.addCase(postInfo.rejected, (state, action) => {
state.request.status = 'failed';
state.request.error = action.error.message as string;
})
builder.addCase(postSales.fulfilled, (state, action) => {
state.request.status = 'succeeded';
state.model = action.payload;
}
builder.addCase(postSales.rejected, (state, action) => {
state.request.status = 'failed';
state.request.error = action.error.message as string;
})
},
})
...
const store = configureStore({
reducer:
postInfoSlice.reducer
});
export type RootState = ReturnType<typeof store.getState>;
constant user = useSelector((state: RootState) => state.postState.user);
const sendInfoRequest = async () => {
try {
const infoObjRequest: InfoRequest = {
firstName: 'John',
lastName: 'Smith'
};
await dispatch(postInfo(infoObjRequest)).unwrap();
} catch (err) {
console.log('rejected for post /info', err);
}
};
const sendSalesRequest = async () => {
try {
const salesObjRequest: SalesRequest = {
firstName: 'John',
lastName: 'Smith',
userId: user?.id
};
await dispatch(postSales(salesObjRequest)).unwrap();
} catch (err) {
console.log('rejected for post /sales', err);
}
};
// Here is where I am dispatching both post where sendSalesRequest can't get the user id from previous postInfo.
sendInfoRequest();
sendSalesRequest();
为什么不在请求中将 ID 作为变量传递?
//is user null or not initialized?
sendInfoRequest(user?.id);
sendSalesRequest(user?.id);
显式发送内容没有错——尤其是在异步上下文中(也更容易测试)。
我认为更大的问题是你的状态可能不是你所期望的(比如 null)。根据我的经验,让事情尽可能简单明确是最有意义的。
回复评论 我在理解你的问题时遇到一些困难,但如果我理解你基本上想要做的逻辑:
-> Send request -> get ID -> use ID
从根本上说,如果不知道 ID,就无法预先完成。您可能想要的是:
-> Send request (wait)
-> with data do {
action1, action2, etc...
}
没有足够的代码可以为您提供除此之外的任何真实信息。如果用户 ID 在您所在的州不存在,您需要请求并使用它。在 redux 中通常看起来像
//And please forgive me, there are A LOT of different ways to write this
...
const doAfterUserIdExists = (userId) => {
dispatch(a)
dispatch(b)
...
dispatch(x)
}
dispatch( initialAction(doAfterUserIdExists) )
//--in the backend
export const initialAction = (callback) => {
return dispatch => {
//do some business logic
...
const user = new User()//ID is created
if(callback) {
callback(user)
}
dispatch({
type: CASCADE_USER_FUNCTION,
user: user,
})
}
}
这与您正在做的并没有什么不同,只是它具有线性流程。 Promise.all()
也不可行,因为它会同时 运行 您的所有事件(毫无意义,您首先需要一个 ID)。
这不是一个完美的解决方案,但它可以让您了解如何控制数据流。您还可以研究 Sagas 或其他模式以使“thunks”起作用。或者,您可以翻转它,以便发布信息和销售请求等“子逻辑”在 back-end 中发生(如果它们是交易的一部分)。
这并不神奇,您需要找到适合您的解决方案。我倾向于依靠回调,因为它们是线性流程,但有许多不同的模式。我发现这个最容易阅读。