正确的代码流程:调度动作并阻止,或者如果调度它们则提前验证?

问题描述 投票:0回答:2

这是我前端开发自学一年后在Stackoverflow上的第一个问题。我已经为我的疑问找到了答案,但由于这些问题第三次出现,我认为现在是时候向网络提问了。

我正在尝试构建什么

我正在尝试建立一个图书馆服务,访客用户可以登录、预订书籍、添加到愿望清单、归还等。对于前端,我使用

react
react-router
react-bootstrap
 redux-toolkit
。由于我对后端还不了解,所以我使用
json-server
获取数据,它监视一个简单的数据库,其中有两个大对象:
users
和书籍
catalogue

我认为应用程序流程

代码中有一个

<Catalogue />
组件,它向
json-server' to get the data (with 
useEffect
), which is stored in the state. When data is fetched, it renders 
` 组件发送请求,其中包含必要的信息和两个按钮。其中一个是打算预订一本书。预订按钮背后的逻辑是:

  • 验证如果当前用户不是管理员
  • 验证如果当前用户已经预订了这本书
  • 验证如果数据库中至少有一本要预订的书

仅当一切正常时,代码才会调度使用

createAsyncThunk
中的
catalogueSlice
创建的操作。在这个 thunk 中,它从数据库中删除了这本书的副本,并将结果传递给
extrareducers
来更新状态。 handleClick 函数是
async
并等待此操作结束。操作完成后,代码将调度另一个操作,即使用
createAsyncThunk
中的
userSlice
创建的操作,该操作会更新数据库,将该书添加到该用户的当前预订中,并且像另一个 thunk 一样,将结果传递给状态,并更新用户的状态。

我的疑惑和问题

我的主要问题

  1. 上述用于验证用户、当前预订以及数据库中图书是否存在的 IF 语句的正确位置在哪里?在 React 组件中还是在 createAsyncThunk 中?我的意思是:验证是否必须分派某个操作更好,还是分派该操作并在之后阻止它更好?例如,使用
    dispatch
    在 thunk 中调用
    thunkAPI
    可以吗?

我的其他疑问

  1. 使用

    useAppSelector
    检索状态通常更好,还是在可能的情况下通过子级
    props
    传递状态?

  2. 到目前为止,我已经有了

    reserve
    addToWishlist
    login
    register
    ,它们都是用
    createAsyncThunk
    创建的,并且在切片的
    extrareducers
    中产生了大量代码。我计划添加更多内容,这将是向服务器发送请求的其他 thunk。这个工作流程可以吗?我在后端犯了一些严重的逻辑错误?

  3. 我不明白,这就是

    thunk
    middleware
    之间的区别。有什么有用的资源吗

这是发送请求的两个主要 thunk。抱歉,他们不是那么干净,但我认为这足以理解这个问题。

export const patchCatalogue = createAsyncThunk(
  'catalogue/patch',
  async ({book, userInfo}: {
    book: IBook;
    userInfo: IUserInfo;
  }, thunkAPI) => {
    const {
      id: bookId,
      book_status: {
        copies,
        history,
        current
      }
    } = book;
    const { 
      id: userId, 
      username 
    } = userInfo;
    try {
      const response = await axios.patch(
        `http://localhost:5000/catalogue/${bookId}`,
        {
          book_status: {
            copies: copies - 1,
            current: [...current, [userId, username]],
          }
        });
      if (response.status === 200) {
        const result = await thunkAPI.dispatch(reserve({ book, userInfo }))
        // console.log(result)
        return response.data;
      }
    }
    catch (error) {
      console.error(`PATCH failed - ${error}`)
    }
  },
);
export const reserve = createAsyncThunk(
  'user/reserve',
  async ({ book, userInfo }: {
    book: IBook;
    userInfo: IUserInfo;
  }, thunkAPI) => {
    const {
      id: userId,
      reservations: {
        current,
        history,
      }
    } = userInfo;

    try {
      const response = await axios.patch(`http://localhost:5000/users/${userId}`, 
      {
        reservations: {
          current: [...current, book],
          history: [...history],
        }
      });
      return response.data;
    }
    catch (error) {
      console.error(error)
    }
  }
);

这是 Button 组件,它调度两个操作。

if (userInfo.role === 'user') {
        if (action === 'Book now!') {
          const alreadyBooked = userInfo.reservations.current.find(item => item.id === book.id)
          if (!alreadyBooked) {
            await dispatch(patchCatalogue({ book, userInfo }));
            dispatch(reserve({ book, userInfo }))
          }
          else {
            alert('The book is already reserved!')
          }
        }
reactjs redux redux-toolkit
2个回答
1
投票

主要问题的答案。

据我所知,上述 IF 语句的正确位置React 组件分派操作意味着在App工作流程中涉及Redux Store。所以让商店介入是没有用的,只是为了检查条件。它还有助于保持商店切片中的代码干净。

渴望知道您其他疑问的答案。


1
投票

我认为,对于可用性和用户角色等条件:

  1. 请检查 React 组件,以便在不满足条件时呈现
    disabled
    按钮。
  2. 这会首先阻止调度运行,并且还可以显示诸如
    "out of stock", "already reserved"
    之类的帮助文本,以获得更好的用户体验。
  3. 调用api时,在写入数据库之前,后端可以再次进行验证,有严格的安全规则。
© www.soinside.com 2019 - 2024. All rights reserved.