Marco Pestrin
Marco Pestrin

Reputation: 404

Material UI React - Autocomplete - How to reset the internal state

My goal is to reset the internal state of Autocomplete Material-UI's component.

My custom component is rendered N times in my cycle

{branches.map((branch, index) => {
    return (
        <BranchSetting
            key={index}
            index={index}
            data={branch}
            removeBranch={removeBranch}
        />

    )
})}

branch is my hook state.

This is my removeBranch function:

const removeBranch = (index) => {
    let listBranch = branches;
    listBranch.splice(index, 1);
    setBranches([...listBranch]);
}

Every time I delete an item to my array branch, everything works fine except the Autocomplete.

This is my BranchSetting component:

import React, { useState, useEffect } from "react";
import Autocomplete from '@material-ui/lab/Autocomplete';

const BranchSettings = ({ removeBranch, index, branchModify, data }) => {
    const [ brands, setBrands ] = useState(data.brands);

    const handleBrandSelected = (event, payload) => {
        const values = payload.map(item => item.value);
        setBrands(values);
    }

    useEffect(() => {
        setBrands(data.brands);
    }, [data])

    return (
        <>
            <Autocomplete
                id={'branch-brand'}
                multiple
                disableCloseOnSelect
                options={carsBrand}
                getOptionLabel={(carsBrand) => carsBrand.label}
                onChange={handleBrandSelected}
                renderTags={(value, getTagProps) =>
                    value.map((option, index) => (
                        <Chip
                            variant="outlined"
                            label={option.value}
                            size="small"
                            {...getTagProps({ index })}
                        />
                    ))
                }
                renderInput={(params) => {
                    return (
                        <TextField
                            {...params}
                            variant="filled"
                            fullWidth
                            label={'brand'}
                        />
                    )
                }}    
            />
        </>
    )
}
export default BranchSettings

carsBrand it is my data source that in the example I avoided writing the population. It's an array

Everytime I try to delete an item, Autocomplete keep the state of the component ad the prev position. I'm looking a way to reset all the internal state of Autocomplete component. The status I refer to can be seen with the devToolBar

enter image description here

I'm looking a good way to keep the items selected properly or that every time the component has changed, rerender the Autocomplete component.

Upvotes: 3

Views: 7906

Answers (2)

Marco Pestrin
Marco Pestrin

Reputation: 404

I resolved the problem.

The problem was that Autocomplete component need to input an array of objects with label and value keys.

In the function handleBrandSelected I saved into my brands status just the value. I should have saved the whole object because then it must be sent as input in Autocomplete with the props value. And to handle the object I should have also used props getOptionSelected.

No problems with the remove function, and no problems with indexes. Only the values selected in inputs and compliant with the documentation were missing. So this is the new code

import React, { useState, useEffect } from "react";
import Autocomplete from '@material-ui/lab/Autocomplete';

const BranchSettings = ({ removeBranch, index, branchModify, data }) => {
    const [ brands, setBrands ] = useState(data.brands);

    const handleBrandSelected = (event, payload) => setBrands(payload);

    useEffect(() => {
        setBrands(data.brands);
    }, [data])

    return (
        <>
            <Autocomplete
                id={'branch-brand'}
                multiple
                disableCloseOnSelect
                options={carsBrand}
                getOptionLabel={(carsBrand) => carsBrand.label}
                onChange={handleBrandSelected}
                renderTags={(value, getTagProps) =>
                    value.map((option, index) => (
                        <Chip
                            variant="outlined"
                            label={option.value}
                            size="small"
                            {...getTagProps({ index })}
                        />
                    ))
                }
                renderInput={(params) => {
                    return (
                        <TextField
                            {...params}
                            variant="filled"
                            fullWidth
                            label={'brand'}
                        />
                    )
                }}
                getOptionSelected={(option, value) => option.value === value.value}
                value={brands}  
            />
        </>
    )
}
export default BranchSettings

Upvotes: 4

Mohamed Ramrami
Mohamed Ramrami

Reputation: 12691

This problem is probably caused by using the array index as a key in <BranchSetting key={index}. I recommend that you add a unique id when creating the branch object, and use that id as a key instead. You can use performance.now() or a small lib like nanoid.

You can read more about the negative impacts of using an index as a key here.

Upvotes: 0

Related Questions