我有一个围绕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
…这就是结果:链接
debounceLoadData将是每个渲染的新功能。您可以使用该useCallback挂钩来确保在渲染之间持久保留相同的功能,并且该功能将按预期工作。
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>