简体   繁体   English

如何在这个 React 组件中去抖动搜索 function?

[英]How to debounce search function in this React Component?

I have a component which gets a list of employees as a prop.我有一个组件,它获取员工列表作为道具。 I've also created an input element for filtering the list by string.我还创建了一个输入元素,用于按字符串过滤列表。 I moved filtering logic into a function which expects a list of data and a search value so it could return filtered list.我将过滤逻辑移动到 function 中,它需要一个数据列表和一个搜索值,因此它可以返回过滤后的列表。

I want to add lodash debounce to search input, so whenever user types something, it would wait 1 second and filter the list out.我想在搜索输入中添加 lodash debounce,所以每当用户输入内容时,它会等待 1 秒并将列表过滤掉。

import React from 'react';
import _ from "lodash"

import { IEmployee } from '../../../store/EmployeesStore/reducer'

import AddEmployee from '../AddEmployee/AddEmployee';
import EmployeeItem from './EmployeeItem/EmployeeItem';

import { TextField } from '@material-ui/core';
import InputAdornment from '@material-ui/core/InputAdornment';
import SearchIcon from '@material-ui/icons/Search';

export interface EmployeeProps {
  employees: IEmployee[];
}

class EmployeeList extends React.Component<EmployeeProps> {
  state = {
    searchValue: ''
  };

//function which returns filtered list
  filterList = (employeesList: IEmployee[], searchValue: string) => { 

    return employeesList.filter((item: any) => {
      const fullName = `${item.firstName}${item.lastName}`.toLowerCase();
      const reversedFullName = `${item.lastName}${item.firstName}`.toLowerCase();
      const trimmedSearchValue = searchValue
        .replace(/\s+/g, '')
        .toLowerCase();
      return (
        fullName.includes(trimmedSearchValue) ||
        reversedFullName.includes(trimmedSearchValue)
      );
    });
  };

  render() {
    // saving filtered list data in filteredList variable
    let filteredList = this.filterList(this.props.employees, this.state.searchValue)
      
    return (
      <>
        <AddEmployee />
        <TextField
          style={{ marginLeft: '20px' }}
          size="medium"
          id="input-with-icon-textfield"
          variant="outlined"
          value={this.state.searchValue}
          onChange={(e) => this.setState({ searchValue: e.target.value })}
          InputProps={{
            endAdornment: (
              <InputAdornment position="end">
                <SearchIcon />
              </InputAdornment>
            ),
          }}
          InputLabelProps={{
            shrink: true,
          }}
        />
        <div>
          <ul
            style={{
              margin: '0px',
              padding: '0px',
              listStyle: 'none',
              display: 'flex',
              flexWrap: 'wrap',
            }}
          >
            {filteredList.map((employee) => {
              return <EmployeeItem key={employee.id} {...employee} />;
            })}
          </ul>
        </div>
      </>
    );
  }
}

export default EmployeeList;

Where should I add the _.debounce function and how?我应该在哪里添加 _.debounce function 以及如何添加?

You should not be calling your filterList function in return statement, instead of that it must be called on onChange of TextField.您不应该在 return 语句中调用您的 filterList function,而是必须在 TextField 的 onChange 上调用它。

Something like this:像这样的东西:

handleChange = (e) => {
    this.setState({ searchValue: e.target.value })};
    const debouncedCall = _.debounce(() => this.filterList(this.props.employees, e.target.value), 1000);
    debouncedCall();    
}

//Rest of your code

render() {
   <TextField
        onChange={(e) => handleChange(e)}
        ...other attributes
   />
}

Only showing the relevant changes:-仅显示相关更改:-

constructor (props) {
super(props)
this.state = {
    searchValue: ''
  };
this.debouncedHandler = _.debounce(this.handleChange.bind(this),1000);
}
handleChange = (e) => {
    this.setState({ searchValue: e.target.value })};
}
        <TextField
          style={{ marginLeft: '20px' }}
          size="medium"
          id="input-with-icon-textfield"
          variant="outlined"
          value={this.state.searchValue}
          onChange={this.debouncedHandler}
          InputProps={{
            endAdornment: (
              <InputAdornment position="end">
                <SearchIcon />
              </InputAdornment>
            ),
          }}
          InputLabelProps={{
            shrink: true,
          }}
        />

Explanation : We are calling the debouncedHandler repeatedly via onChange so we need to ensure that handleChange only gets triggered once that burst of 1000 ms is over and no call to debouncedHandler happened within this duration.解释:我们通过onChange重复调用debouncedHandler ,因此我们需要确保仅在1000毫秒的突发结束后才触发handleChange ,并且在此持续时间内没有调用debouncedHandler If another call to debouncedHandler happens within that burst interval a new burst interval starts.如果在该突发间隔内发生另一个对debouncedHandler的调用,则开始一个新的突发间隔。

From your component's perspective, we are delaying the execution of our main logic which is inside handleChange by 1000 ms everytime unless the user doesn't enter any other character in the TextField component within that 1000ms , once that 1000 ms are over, the setState will get triggered to state the state ---> meaning a re-render -----> meaning new filteredList and it's display to the user.从您的组件的角度来看,除非用户在 1000 毫秒内没有在TextField组件中输入任何其他字符,否则我们每次都会将在handleChange内部的主逻辑的执行延迟1000 1000ms ,一旦1000毫秒结束, setState将被触发到 state state ---> 表示重新渲染 -----> 表示新的过滤列表并将其显示给用户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM