Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delay suggestion time in MUI Autocomplete

Anyone knows how to delay time before it gives suggestions?

As soon as I write the first letter it gives me suggestions, I'd like to delay that, I read through the docs and couldn't find it, maybe it's not possible?

like image 722
Polisas Avatar asked Nov 25 '16 19:11

Polisas


3 Answers

The conventional way is to use debounce or throttle to delay the function call while the user is typing. The delay behaviors are a bit different between them, see here for more info. For this answer I'll use debounce from lodash.

Also please do not copy the most upvoted answer. It is wrong and uses bad practice:

  • It imports the whole lodash package, which contains brazillions of other methods that you probably don't need and will increase your final bundle size. The correct way to do it is to use this import syntax instead:
import debounce from 'lodash/debounce
  • It passes the result of debounce(handleSearch) directly to the onUpdateInput props. debounce is a higher-order function, it is a function factory that creates another function that can be delayed:
const handleSearch = () => { // ... }
const handleSearchDelayed = debounce(handleSearch, 50);

handleSearchDelayed();
handleSearchDelayed();
handleSearchDelayed();

// handleSearchDelayed is called 3 times but handleSearch will only be called 1 time
// 50ms later

This means that the debounce(handleSearch) will create a new function with its own delay timer every time the component is re-render which is every time the user types in the textfield. This will create unexpected side-effects or even make the component not working at all.

The solution is to use useCallback to return the same instance of the delay function when the component re-renders. Below is the minimal working example:

import React, { useCallback, useEffect, useState } from "react";
import Autocomplete from '@mui/lab/Autocomplete';
import TextField from '@mui/material/TextField';
import debounce from "lodash/debounce";
import { getOptionsAsync } from "./options";

function App() {
  const [options, setOptions] = useState([]);
  const [inputValue, setInputValue] = React.useState("");
  const getOptionsDelayed = useCallback(
    debounce((text, callback) => {
      setOptions([]);
      getOptionsAsync(text).then(callback);
    }, 200),
    []
  );

  useEffect(() => {
    getOptionsDelayed(inputValue, (filteredOptions) => {
      setOptions(filteredOptions);
    });
  }, [inputValue, getOptionsDelayed]);

  return (
    <Autocomplete
      options={options}
      getOptionLabel={(option) => option.title}
      filterOptions={(x) => x} // disable filtering on client
      loading={options.length === 0}
      onInputChange={(e, newInputValue) => setInputValue(newInputValue)}
      renderInput={(params) => <TextField {...params} label="Combo box" />}
    />
  );
}

Live Demo

Edit 40811535/delay-suggestion-time-material-ui-autocomplete-component

like image 63
NearHuscarl Avatar answered Nov 12 '22 06:11

NearHuscarl


You can use lodash's debounce() function (basically a little window.setTimeout trick to throttle repeated calls):

import _ from 'lodash';

...

doSearch(text) {
   // Your normal handler here
}

...

// Delay autocomplete until 500 ms after use stops typing
<AutoComplete
  onUpdateInput={_.debounce((value) => doSearch(value), 500)}
  ...
/>
like image 20
Jeff McCloud Avatar answered Nov 12 '22 04:11

Jeff McCloud


There is example from my project with AutoComplete from Antd package:

const { AutoComplete } = antd

const WAIT_INTERVAL = 1000
let timerID

class Test extends React.Component {

    handleSearch = (query) => {
        clearTimeout(timerID)

        timerID = setTimeout(() => {
            console.log('some action after delay')
        }, WAIT_INTERVAL)
    }

    render(){
        return (
            <AutoComplete
                ...
                onSearch={handleSearch}
            />
        )
    }
}
like image 5
Hokku San Avatar answered Nov 12 '22 06:11

Hokku San