【问题标题】:wait 500 miliseconds before running react hook在运行反应钩子之前等待 500 毫秒
【发布时间】:2021-04-05 12:10:53
【问题描述】:

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

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 中调用

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

【问题讨论】:

  • 您正在寻找debounce。相信这里已经有答案了:stackoverflow.com/questions/54666401/…
  • 我会将自定义钩子转换为自定义异步函数,并使用 useRef 检测类型区间 onChange。进出口。 > time = useRef(Date.now()) 和里面的 onChange if (Date.now() &gt; time + 500) { asyn fetch(); time.curent = Date.now() }

标签: javascript reactjs react-hooks


【解决方案1】:

您可以使用额外的状态来消除您的价值。一旦 query 被更改,我们将启动一个 500 毫秒的计时器,它将设置 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>
  );
}

【讨论】:

    【解决方案2】:

    我将更改 useProducts 挂钩以接受去抖时间作为参数,并让它仅在去抖时间结束后才调用 axios:

    useProducts(query, 500);
    
    export default function useProducts(searchQuery, debounceTime = 0) {
        const [products, setProducts] = useContext(ProductContext);
        const [isLoading, setIsloading] = useState(true);
        const [timeoutId, setTimeoutId] = useState();
        useEffect(() => {
            clearTimeout(timeoutId);
            setTimeoutId(setTimeout(() => {
                axios
                    .get(`/shoes?q=${searchQuery ? searchQuery : ''}`)
                    .then((res) => {
                        setProducts(res.data);
                        setIsloading(false);
                    })
                    .catch((err) => {
                        console.error(err);
                    });
            }, debounceTime));
        }, [searchQuery, setProducts]);
        return { products, isLoading };
    }
    

    【讨论】:

      猜你喜欢
      • 2013-07-13
      • 2021-04-27
      • 1970-01-01
      • 2021-08-24
      • 2014-03-14
      • 2012-12-23
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      相关资源
      最近更新 更多