如何通过 RTK 查询阻止或终止 React 中正在进行的请求?

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

我正在 React 应用程序中使用 Redux Toolkit 和 RTK Query,并且我想在用户单击新按钮时取消或终止正在进行的 API 请求。我想确保如果在前一个请求完成之前触发新请求,则前一个请求将被中止或阻止完成。

问题:

我想确保,如果用户单击按钮加载新部分,则先前单击按钮的任何正在进行的请求都将被取消,并且不会干扰新请求。但是,我遇到了以下问题:

The ongoing request is not being killed.
The new request is being initiated regardless of the previous one.

预期行为:

我希望当用户单击新按钮加载新部分(例如“帖子”、“评论”)时,任何正在进行的请求(例如单击的上一个按钮)都应中止或阻止完成。新请求应立即发送,并且不应收到先前请求的响应。 StackBlitz 链接:https://stackblitz.com/edit/vitejs-vite-54uhcypb?file=src%2FApp.tsx,src%2Fservice.tsx&terminal=dev

(我知道我可以在需要时禁用按钮,但我不想要/喜欢这种方法)

任何人都可以建议如何正确实现这一点或如何在 RTK 查询中有效地终止请求?

reactjs redux-toolkit rtk-query
1个回答
0
投票

重构 adminAPI 以包含通用端点 在 adminAPI 中添加单个动态端点以动态选择资源。 fetchResource 端点根据调用期间传入的资源类型动态构建查询 URL。

useLazyFetchResourceQuery 挂钩用于在单击按钮时手动触发查询。

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const adminAPI = createApi({
  reducerPath: 'dashboardApi',
  baseQuery: fetchBaseQuery({
    baseUrl: 'https://jsonplaceholder.typicode.com',
  }),
  endpoints: (builder) => ({
    fetchResource: builder.query({
      query: ({ resourceType, params }) => {
        // Add query parameters dynamically
        const queryParams = params
          ? '?' +
            Object.entries(params)
              .map(([key, value]) => `${key}=${value}`)
              .join('&')
          : '';
        return `/${resourceType}${queryParams}`;
      },
    }),
  }),
});

export const { useLazyFetchResourceQuery } = adminAPI;

用单个动态查询替换当前的多个挂钩,并包含基于资源类型及其关联查询参数处理独特功能的逻辑。

import './App.css';
import React, { useState } from 'react';
import { useLazyFetchResourceQuery } from './service';

function App() {
  const [resourceType, setResourceType] = useState(null); // Track current resource type
  const [queryParams, setQueryParams] = useState(null); // Track any dynamic params

  const [fetchResource, { data, isFetching, isError }] = useLazyFetchResourceQuery();

  const handleFetchResource = (type) => {
    setResourceType(type);

    // Customize parameters or behavior for each resource
    switch (type) {
      case 'posts':
        setQueryParams({ _limit: 10, _page: 1 }); // Example: Pagination for posts
        break;
      case 'comments':
        setQueryParams({ _limit: 20 }); // Comments have a custom limit
        break;
      case 'albums':
        setQueryParams(null); // No special params for albums
        break;
      case 'photos':
        setQueryParams({ _limit: 5 }); // Load fewer photos
        break;
      case 'todos':
        setQueryParams(null); // Name or filter for Todos (if needed)
        break;
      case 'users':
        setQueryParams(null); // Users may not require parameters
        break;
      default:
        setQueryParams(null);
    }

    // Trigger the dynamic query with both resource type and its specific params
    fetchResource({ resourceType: type, params: queryParams });
  };

  return (
    <>
      <button onClick={() => handleFetchResource('posts')}>Load Posts</button>
      <button onClick={() => handleFetchResource('comments')}>Load Comments</button>
      <button onClick={() => handleFetchResource('albums')}>Load Albums</button>
      <button onClick={() => handleFetchResource('photos')}>Load Photos</button>
      <button onClick={() => handleFetchResource('todos')}>Load Todos</button>
      <button onClick={() => handleFetchResource('users')}>Load Users</button>
      <br />

      {/* Show loading state */}
      {isFetching && <p>Loading {resourceType}...</p>}

      {/* Handle error state */}
      {isError && <p style={{ color: 'red' }}>Error loading {resourceType} data.</p>}

      {/* Show data dynamically with resource-specific logic */}
      {data && (
        <div>
          <h3>{resourceType.charAt(0).toUpperCase() + resourceType.slice(1)}</h3>

          <ul>
            {/* Customize how to show data based on the resource */}
            {Array.isArray(data) &&
              data.map((item, index) => {
                switch (resourceType) {
                  case 'posts':
                    return <li key={index}><strong>{item.title}</strong> - {item.body}</li>; 
                  case 'comments':
                    return <li key={index}>"{item.body}" by User {item.email}</li>; 
                  case 'albums':
                    return <li key={index}>{item.title}</li>; 
                  case 'photos':
                    return <li key={index}><img src={item.thumbnailUrl} alt={item.title} /> {item.title}</li>; 
                  case 'todos':
                    return <li key={index}>{item.title} - {item.completed ? '✅' : '❌'}</li>; 
                  case 'users':
                    return (
                      <li key={index}>
                        {item.name} - {item.email}
                      </li>
                    ); 
                }
              })}
          </ul>
        </div>
      )}
    </>
  );
}

export default App;
© www.soinside.com 2019 - 2024. All rights reserved.