skip to Main Content

I have this Autocomplete component

<Autocomplete
                    filterOptions={(x) => x}
                    options={items}
                    getOptionLabel={(option) =>
                      `${option.code} - ${option.name}`
                    }
                    onInputChange={(e, value) => {
                      console.log(value);
                      setAutoComplete(value);
                    }}
                    onChange={(e, value) => {
                      //Change state of some other fields
                    }}
                    noOptionsText={false}
                    renderInput={(params) => (
                      <TextField
                        {...params}
                      />
                    )}
                    value={
                      items.filter((item) => item.id == row.item_id)[0] || null
                    }
/>

I’m trying to make a server search and get the new items value, the problem is that this results in an infinite loop as when the value of the autocomplete is changed to another item, the onInputChange is also called, Making another request to get the new items value thus making changing input again and again until the server hangs up on the request.
However, this only happens when the value of the Autocomplete is controlled, I have another component that’s uncontrolled and it doesn’t produce this infinite loop.
How can I fix this?

2

Answers


  1. Chosen as BEST ANSWER

    So this might seem weird. But I fixed the error by setting the setAutocomplete to take the value of the e?.target.value of the onInputchange function, instead of the value itself. This somehow fixed the problem.


  2. This happens because the reference to the selected object in value keeps changing.

    When you download a new list of items and filter the item from the new list in the value prop, even though the contents of the items are identical, the new item is a different object in the browser’s memory. MUI interprets it as a value change so it triggers the onInputChange callback, which causes new data to fetch, which causes the value to change, … – you get an infinite loop.

    Here is a CodeSandbox I prepared that demonstrates the issue: https://codesandbox.io/s/peaceful-dawn-928gg2?file=/src/Demo.tsx

    I think the easiest way to fix that would be to use the IDs of your items as options (instead of entire objects) and then find the correct item inside the getOptionLabel function.

    IDs are strings or numbers (primitive types) so they are compared by value instead of by reference, which means that the issue will be solved. This solution will not work if your ID field is an object or an array!

    That would mean changing the following props in your code:

    options={items.map(item => item.id)}
    getOptionLabel={(id) =>
      {
        const option = items.find(item => item.id === id);
        return `${option.code} - ${option.name}`;
      }
    }
    value={row.item_id}
    

    You might also need to make changes to the onInputChange prop and handle undefined/null in getOptionLabel and value but it’s difficult to tell exactly without seeing more of your code.

    You can learn more about that issue in the documentation: https://mui.com/material-ui/react-autocomplete/#controlled-states (see the yellow warning section)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search