首页 > 解决方案 > 在运行反应钩子之前等待 500 毫秒

问题描述

我已经建立了这个自定义反应钩子:

import { useEffect, useContext, useState } from 'react';
import { ProductContext } from '../contexts';
import axios from 'axios';

export default function useProducts(searchQuery) {
  const [products, setProducts] = useContext(ProductContext);
  const [isLoading, setIsloading] = useState(true);

  useEffect(() => {
    axios
      .get(`/shoes?q=${searchQuery ? searchQuery : ''}`)
      .then((res) => {
        setProducts(res.data);
        setIsloading(false);
      })
      .catch((err) => {
        console.error(err);
      });
  }, [searchQuery, setProducts]);

  return { products, isLoading };
}

它基本上根据我传入的查询字符串获取一些数据。查询字符串来自输入字段:

import React, { useState } from 'react';
import { FiSearch } from 'react-icons/fi';
import { useProducts } from '../../hooks';

export default function SearchBar() {
  const [query, setQuery] = useState('');

  const handleChange = (e) => {
    e.preventDefault();
    setQuery(e.target.value);
  };

  useProducts(query);

  return (
    <div className="search-form">
      <FiSearch className="search-form__icon" />
      <input
        type="text"
        className="search-form__input"
        placeholder="Search for brands or shoes..."
        onChange={handleChange}
      />
    </div>
  );
}

问题是它会在用户输入时获取。我希望它在用户没有输入 500 毫秒后获取。

我尝试的是:

  setTimeout(() => {
    useProducts(query);
  }, 500);

但这会返回一个错误说:

src\components\header\SearchBar.js 第 14:5 行:不能在回调中调用 React Hook “useProducts”。React Hooks 必须在 React 函数组件或自定义 React Hook 函数中调用 react-hooks/rules-of-hooks

搜索关键字以了解有关每个错误的更多信息。

标签: javascriptreactjsreact-hooks

解决方案


您可以使用额外的状态来消除您的价值。更改后,我们会启动一个 500 毫秒的计时器,该计时器将query设置debounced. 但是,如果效果重新运行,我们会清除该计时器并设置一个新计时器。

import React, { useState, useEffect } from 'react';
import { FiSearch } from 'react-icons/fi';
import { useProducts } from '../../hooks';

export default function SearchBar() {
  const [query, setQuery] = useState('');
  const [debounced, setDebounced] = useState('');

  useEffect(() => {
    const timeout = setTimeout(() => {
      setDebounced(query);
    }, 500);
    return () => { clearTimeout(timeout) }
  }, [query])

  const handleChange = (e) => {
    e.preventDefault();
    setQuery(e.target.value);
  };

  useProducts(debounced);

  return (
    <div className="search-form">
      <FiSearch className="search-form__icon" />
      <input
        type="text"
        className="search-form__input"
        placeholder="Search for brands or shoes..."
        onChange={handleChange}
      />
    </div>
  );
}

推荐阅读