reactjs - Redux 存储在使用函数时落后了一步
问题描述
我有一个具有书评功能的应用程序。我正在使用谷歌图书 api。addReview 函数基本上分为两部分。第一个将一本书添加到我的后端,当您单击“添加评论”按钮时,另一个添加该书的评论。它还通过来自 google api 的 book_api_id 检查这本书是否已经在后端。我已经有了这个功能。我唯一的问题是在添加书籍功能中,我无法立即获得新创建的书籍 ID。所以它会出错,因为我的评论依赖于 book_id(不同于 book_api_id)来关联评论。
我现在的问题是,如果我从零开始创建评论(清除本地存储和 redux-persist 并启动一个新的 localhost:3000 应用程序,当我为一本不存在的书添加书评时,它会添加该书但随后抛出一个错误,即 book_id for review 为空,但在 redux 商店的下一个状态,它显示 book_id。
在点击添加评论之前如何获得该价值?
我尝试用 try catch 包装我的 redux 函数,但我没有得到任何结果。目前我的很多功能都在使用 Async-Await,它在检查一本书是否存在方面非常有效,然后如果这本书存在,则使用该 ID。我知道这是一个异步函数,因为做了一些研究,redux 下一个状态基本上在该函数中排队。
This is part of a bigger code, but it's an else block in a function so think of this as:
How can I use next state right away in the same function?
else {
props.addBook(bookInfo)
let newId = parseInt(props.bookId) // this id is from the redux store
if (values.rating && values.review){
let newBookReview = {
book_id: newId,
user_id: props.currentUser.id,
rating: parseFloat(values.rating),
content: values.review
}
props.addReview(newBookReview); // this is the add review function
} // end of else
// My add book function (this uses graphQL) from book_action file
export function addBook(book){
return dispatch => {
dispatch({type: ADDING_BOOK});
const token = localStorage.getItem("token");
const client = new ApolloClient({
uri: "http://localhost:9090",
headers: { authorization: token }
});
client
.mutate({
mutation: ADD_BOOK_MUTATION,
variables: {
input: book
}
})
.then(response => {
dispatch({
type: BOOK_ADDED,
payload: response.data.addBook //this payload contains the bookid
})
})
.catch(error => {
dispatch({
type: BOOK_ERROR,
payload: "Unable to add book"
})
})
}
}
// My add review function from my review_action file.
export function addReview(review){
return dispatch => {
dispatch({type: ADDING_REVIEW});
const token = localStorage.getItem("token");
const client = new ApolloClient({
uri: "http://localhost:9090",
headers: { authorization: token }
});
client
.mutate({
mutation: ADD_REVIEW_MUTATION,
variables: {
input: review
}
})
.then(response => {
console.log('success', response)
dispatch({
type: REVIEW_ADDED,
payload: response.data.addReview
})
})
.catch(error => {
console.log('review error',error)
dispatch({
type: REVIEW_ERROR,
payload: "Unable to add a review"
})
})
}
}
我得到的是一个空值,但在 redux-logger 的下一个状态下,它显示了我可以获得 Id 的书籍数据。
我的错误是 addReview 失败,因为在当前的 redux 状态下,book 为空。
解决方案
Redux 存储在使用函数时落后了一步
这是预期的行为。商店将通过减速器在每次调度时更新。但是此更新用于下一次渲染。
记住这一点,最好的方法就是进行重构:
- 将值作为有效负载传递
export function addBook(book){
return dispatch => {
dispatch({
type: ADDING_BOOK,
payload: book,
});
}
}
export function addReview(review){
return dispatch => {
dispatch({
type: ADDING_REVIEW,
payload: review,
});
}
}
connect
通过然后做一个突变来监听组件更新
mapStateToProps(state) {
const { book } = state;
return {
book,
}
}
componentDidUpdate(prevProps) {
// only do a review if a book is already available
if (!prevProps.book && this.props.book) {
// do a review mutation
// client.mutate(...)
}
}
使用 Redux Saga
你也可以使用redux-saga。添加观察者ADDING_BOOK
并ADDING_REVIEW
采取行动来进行突变。这样,store 首先通过 reducer 更新,然后控制权返回到 saga。
function* root() {
yield takeEvery(ADDING_BOOK, watchAddBook);
yield takeEvery(ADDING_REVIEW, watchAddReview);
}
function* watchAddBook(action) {
const { payload } = action; // book payload
// client.mutate(...)
}
function* watchAddReview(action) {
const { payload } = action; // review payload
// client.mutate(...)
}
推荐阅读
- python-2.7 - 在 Apache Spark 2.3.1 中,我们可以在哪种部署模式下“不”向集群添加节点
- css - 在引导程序 3 中,多个 div 重叠,它们之间没有边距
- php - 图片按钮不工作,但正常按钮工作:php
- c++ - CMake 缓存窗口
- angular - 离子 - 登录后黑屏只是闪烁/闪烁一段时间
- sql - SSIS 中参数的多个值(OLEDB 源)
- c# - 从线程 c# 更改表单属性
- c# - 以 SQL 作为数据源的图表
- sql - ORA-00904: "DAYS": 无效标识符
- vb.net - 当 SUM 计算结果为 false 时,报表生成器表达式返回字符串