reactjs 如何实现rtk的去抖动createApi查询

ffscu2ro  于 2022-12-18  发布在  React
关注(0)|答案(3)|浏览(221)

有人能帮助我使用creatApi和redux工具包中的查询实现来实现去抖动功能吗?
先谢了。

mitkmikd

mitkmikd1#

我个人并没有发现RTK Query中有任何开箱即用的反跳实现。但是你可以自己实现它。
定义一个API,我用的是开放库的api:

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

type BooksSearchResult = {
  docs: Book[];
};

type Book = {
  key: string;
  title: string;
  author_name: string;
  first_publish_year: number;
};

export const booksApi = createApi({
  reducerPath: 'booksApi',
  baseQuery: fetchBaseQuery({ baseUrl: 'http://openlibrary.org/' }),
  endpoints: builder => ({
    searchBooks: builder.query<BooksSearchResult, string>({
      query: term => `search.json?q=${encodeURIComponent(term)}`,
    }),
  }),
});

export const { useSearchBooksQuery } = booksApi;

接下来你需要的是去抖动钩子,它保证一些值只在指定的延迟后改变:

function useDebounce(value: string, delay: number): string {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debouncedValue;
}

在搜索表单上使用防反跳挂钩:

import React, { useEffect, useState } from "react";
import BookSearchResults from "./BookSearchResults";

function useDebounce(value: string, delay: number): string {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debouncedValue;
}

const DebounceExample: React.FC = () => {
  const [searchTerm, setSearchTerm] = useState("");
  const debouncedSearchTerm = useDebounce(searchTerm, 500);

  return (
    <React.Fragment>
      <h1>Debounce example</h1>
      <p>Start typing some book name. Search starts at length 5</p>
      <input
        className="search-input"
        type="text"
        placeholder="Search books"
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
      />
      <BookSearchResults searchTerm={debouncedSearchTerm}></BookSearchResults>
    </React.Fragment>
  );
};

export default DebounceExample;


在搜索结果组件中使用搜索查询钩子。它使用自己的状态来表示搜索项值,如果你想为去抖动值添加额外的“过滤器”,这是非常方便的(例如,只有当搜索项的长度大于某个值时才开始查询)。

import React, { useState, useEffect } from "react";
import { useSearchBooksQuery } from "./booksApi";

type BookSearchResultsProps = {
  searchTerm: string;
};

const BookSearchResults: React.FC<BookSearchResultsProps> = ({
  searchTerm
}: BookSearchResultsProps) => {
  const [filteredSearchTerm, setFilteredSearchTerm] = useState(searchTerm);
  const { data, error, isLoading, isFetching } = useSearchBooksQuery(
    filteredSearchTerm
  );
  const books = data?.docs ?? [];

  useEffect(() => {
    if (searchTerm.length === 0 || searchTerm.length > 4) {
      setFilteredSearchTerm(searchTerm);
    }
  }, [searchTerm]);

  if (error) {
    return <div className="text-hint">Error while fetching books</div>;
  }

  if (isLoading) {
    return <div className="text-hint">Loading books...</div>;
  }

  if (isFetching) {
    return <div className="text-hint">Fetching books...</div>;
  }

  if (books.length === 0) {
    return <div className="text-hint">No books found</div>;
  }

  return (
    <ul>
      {books.map(({ key, title, author_name, first_publish_year }) => (
        <li key={key}>
          {author_name}: {title}, {first_publish_year}
        </li>
      ))}
    </ul>
  );
};

export default BookSearchResults;

完整示例可在here上找到。

zte4gxcn

zte4gxcn2#

在我的情况下,下面的解决方案效果很好。
我使用了分量去抖的方法。使用任何去抖fn,以我的方式:

npm i debounce

然后在组件中

import debounce from 'debounce';

const Component = () => {
  const { data, refetch } = useYourQuery();
  const [mutate] = useYourMutation();

  const handleDebouncedRequest = debouce(async () => {
        try {
            // you can use refetch or laze query way
            await refetch();
            await mutate();
        } catch {}
    }, 2000);

   // ...other component logic
}
nnvyjq4y

nnvyjq4y3#

在第一次呈现之后,我们的request钩子将尝试发送请求,我们可以使用skipToken绕过它,直到searchTerm返回某个值,才发送请求

import { useDebounce } from 'use-debounce'
import { skipToken } from '@reduxjs/toolkit/query'

const [storeName, setStoreName] = useState('')
const [searchTerm] = useDebounce(storeName, 1500)

const { data } = useSearchStoresRequestQuery(searchTerm || skipToken)

有关skipToken的详细信息:https://redux-toolkit.js.org/rtk-query/usage/conditional-fetching
也在我的useSearchStoresRequestQuery中

endpoints: (builder) => ({
      getStoresWithSearchRequest: builder.query({
         query: ({searchTerm}) => {
            return {
               url: `admin/v1/stores?searchTerm?${searchTerm}`,
               method: 'GET',
       
            }
         },

相关问题