React 功能组件中的 lodash 去抖动不起作用



我有一个围绕 React Table 组件构建的功能组件,它使用 Apollo GraphQL 客户端进行服务器端分页和搜索。我正在尝试为搜索实现去抖动,以便在用户停止使用该值键入后仅对服务器执行一个查询。我已经尝试了 lodash 去抖动和很棒的去抖动承诺解决方案,但仍然对搜索字段中键入的每个字符对服务器执行查询。

这是我的组件(编辑了不相关的信息(:

import React, {useEffect, useState} from 'react';
import ReactTable from "react-table";
import _ from 'lodash';
import classnames from 'classnames';
import "react-table/react-table.css";
import PaginationComponent from "./PaginationComponent";
import LoadingComponent from "./LoadingComponent";
import {Button, Icon} from "../../elements";
import PropTypes from 'prop-types';
import Card from "../card/Card";
import './data-table.css';
import debounce from 'lodash/debounce';
function DataTable(props) {
    const [searchText, setSearchText] = useState('');
     const [showSearchBar, setShowSearchBar] = useState(false);
    const handleFilterChange = (e) => {
        let searchText = e.target.value;
        setSearchText(searchText);
        if (searchText) {
            debounceLoadData({
                columns: searchableColumns,
                value: searchText
            });
        }
    };
    const loadData = (filter) => {
        // grab one extra record to see if we need a 'next' button
        const limit = pageSize + 1;
        const offset = pageSize * page;
        if (props.loadData) {
            props.loadData({
                variables: {
                    hideLoader: true,
                    opts: {
                        offset,
                        limit,
                        orderBy,
                        filter,
                        includeCnt: props.totalCnt > 0
                    }
                },
                updateQuery: (prev, {fetchMoreResult}) => {
                    if (!fetchMoreResult) return prev;
                    return Object.assign({}, prev, {
                        [props.propName]: [...fetchMoreResult[props.propName]]
                    });
                }
            }).catch(function (error) {
                console.error(error);
            })
        }
    };
    const debounceLoadData = debounce((filter) => {
        loadData(filter);
    }, 1000);
    return (
        <div>
            <Card style={{
                border: props.noCardBorder ? 'none' : ''
            }}>
                {showSearchBar ? (
                        <span className="card-header-icon"><Icon className='magnify'/></span>
                        <input
                            autoFocus={true}
                            type="text"
                            className="form-control"
                            onChange={handleFilterChange}
                            value={searchText}
                        />
                        <a href="javascript:void(0)"><Icon className='close' clickable
                                                           onClick={() => {
                                                               setShowSearchBar(false);
                                                               setSearchText('');
                                                           }}/></a>
                ) : (
                        <div>
                           {visibleData.length > 0 && (
                                <li className="icon-action"><a 
href="javascript:void(0)"><Icon className='magnify' onClick= {() => {
    setShowSearchBar(true);
    setSearchText('');
}}/></a>
                                </li>
                            )}
                        </div>
                    )
                )}
                <Card.Body className='flush'>
                    <ReactTable
                        columns={columns}
                        data={visibleData}
                    />
                </Card.Body>
            </Card>
        </div>
    );
}
export default DataTable

。这就是结果:link

debounceLoadData将是每个渲染的一个新函数。您可以使用 useCallback 挂钩来确保在渲染之间保留相同的函数,并且它将按预期工作。

useCallback(debounce(loadData, 1000), []);

const { useState, useCallback } = React;
const { debounce } = _;
function App() {
  const [filter, setFilter] = useState("");
  const debounceLoadData = useCallback(debounce(console.log, 1000), []);
  function handleFilterChange(event) {
    const { value } = event.target;
    setFilter(value);
    debounceLoadData(value);
  }
  return <input value={filter} onChange={handleFilterChange} />;
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

补充一下 Tholle 的答案:如果你想充分利用钩子,你可以使用 useEffect 钩子来观察过滤器的变化,并在发生这种情况时运行 debouncedLoadData 函数:

const { useState, useCallback, useEffect } = React;
const { debounce } = _;
function App() {
  const [filter, setFilter] = useState("");
  const debounceLoadData = useCallback(debounce(fetchData, 1000), []);
  useEffect(() => {
    debounceLoadData(filter);
  }, [filter]);
  function fetchData(filter) {
    console.log(filter);
  }
  return <input value={filter} onChange={event => setFilter(event.target.value)} />;
}
ReactDOM.render(<App />, document.getElementById("root"));

您必须记住渲染之间的去抖动函数。

但是,您不应使用useCallback来记住其他答案中建议的去抖(或限制(函数。 useCallback专为内联功能而设计!

而是使用 useMemo 来记住渲染之间的去抖动函数:

useMemo(() => debounce(loadData, 1000), []);

我希望这篇文章能让你找到解决方案,

您不必使用外部库进行去抖动,您可以按照我的步骤创建自己的自定义钩

步骤(1(:- 创建自定义去抖

  
import { useEffect ,useState} from 'react';

export const  UseDebounce = (value,delay)=>{
  const [debouncedValue,setDebouncedValue]= useState();
useEffect(()=>{
let timer = setTimeout(()=>setDebouncedValue(value),delay)

return ()=> clearTimeout(timer);
},[value])
return debouncedValue
}

步骤(2( :- 现在创建要在其中添加限制的文件

import React from 'react'
import { useEffect } from 'react';
import { useState } from 'react';
import {UseDebounce} from "./UseDebounce";

function Test() {
    const [input, setInput] = useState("");
     const debouncedValue = UseDebounce(input,1000);
  
    
    const handleChange = (e)=>{
        setInput(e.target.value)
    }
    useEffect(()=>{
        UseDebounce&& console.log("UseDebounce",UseDebounce)
    },[UseDebounce])
    

  return (
    <div>
    <input type="text" onChange={handleChange} value={input}/>
    {UseDebounce}
    </div>
  )
}
export default Test;

注意:- 要测试此文件,请先创建 react 应用程序,然后在其中包含我的文件中加入我的文件

希望这个解决方案值得你

最新更新