首页 > 解决方案 > 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 为空。

标签: reactjsasynchronousreduxgraphql

解决方案


Redux 存储在使用函数时落后了一步

这是预期的行为。商店将通过减速器在每次调度时更新。但是此更新用于下一次渲染。

记住这一点,最好的方法就是进行重构:

  1. 将值作为有效负载传递
export function addBook(book){
  return dispatch => {
    dispatch({
      type: ADDING_BOOK,
      payload: book,
    });
  }
}

export function addReview(review){
  return dispatch => {
    dispatch({
      type: ADDING_REVIEW,
      payload: review,
    });
  }
}
  1. 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

你也可以使用。添加观察者ADDING_BOOKADDING_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(...)
}

推荐阅读