I have mutliSelect and my case is: when the Value prop is [] (the multiSelect component get this prop), set my useState also [].
I tried to write something like this:
const [selected, setSelected] = useState([]);
useEffect(() => {
setSelected([]);
}, [Value]);
<Select
style={style}
maxTagCount={0}
maxTagPlaceholder={maxTagPlaceholder}
mode="multiple"
placeholder={placeholder}
showSearch
value={selected} // here I tried to put the Value but not working well
onSelect={(val) => onSelectValueMultiSelect(val, selected, setSelected, options)}
onDeselect={(val) => onDeselectValueMultiSelect(val, selected, setSelected)}>
{childrenOptions}
</Select>
but I get infinite loop error.
the Value array contains arrays form filter data, and on click 'reset filter' button I want to reset my multiSelect field.
I think the problem is when the setSelected([]) called it's render again the Value so the useEffect called again and again.
My MultiSelect component:
import React, { useEffect, useState } from 'react';
import './MultiSelect.scss';
import { maxTagPlaceholder, onSelectValueMultiSelect, onDeselectValueMultiSelect } from '../Services';
import { Select, Checkbox } from 'antd';
const MultiSelect = ({ options, style, onChangeHandle, placeholder, Value }) => {
const [selected, setSelected] = useState([]);
const [childrenOptions, setChildrenOptions] = useState([]);
const { Option } = Select;
const children = [];
useEffect(() => {
options.forEach((option) => {
children.push(
<>
<Option key={option.value}>
<Checkbox className="multi-select-checkbox" checked={selected.some((x) => x === option.value)} />
{option.value}
</Option>
</>
);
});
setChildrenOptions(children);
}, [selected]);
useEffect(() => {
onChangeHandle(selected);
}, [selected]);
useEffect(() => {
setSelected([]);
}, [Value]);
return (
<Select
style={style}
maxTagCount={0}
maxTagPlaceholder={maxTagPlaceholder}
mode="multiple"
placeholder={placeholder}
showSearch
value={selected}
onSelect={(val) => onSelectValueMultiSelect(val, selected, setSelected, options)}
onDeselect={(val) => onDeselectValueMultiSelect(val, selected, setSelected)}>
{childrenOptions}
</Select>
);
};
export default MultiSelect;
If Value is calculated based on selected then this useEffect() is the issue:
useEffect(() => {
setSelected([]);
}, [Value]);
As you said, it will cause an infinite loop as selected changes again and again, causing Value to change as well and the component keeps re-rendering.
Another place to look for error is in your <Select> component callbacks with onSelect and onDeselect. It is not a good idea to pass setSelected as parameter in most circumstances because useState hook has side effects. You don't provide the full code here, but I think it is likely that this also causes state change unstably in your component and causes the re-rendering.
Moreover, you have 2 useEffect() both have [selected] as dependency, so when selected changes it will cause duplicate rendering to the component as well. This is, however, not the cause to your primary issue.
Solution could be using only 1 useEffect() as follow:
Step 1. Regarding your <Select> component callback:
onSelect={handleSelect}
onDeselect={handleDeselect}
const handleSelect = (val) => {
// think about removing setSelected
onSelectValueMultiSelect(val, selected, setSelected, options);
// move this here
onChangeHandle(selected);
// reset selected here if wanted
setSelected([]);
}
const handleDeselect = (val) => {
// think about removing setSelected
onDeselectValueMultiSelect(val, selected, setSelected, options);
// move this here
onChangeHandle(selected);
// reset selected here if wanted
setSelected([]);
}
Step 2. Refactor your useEffect(), using only 1 instead of 3:
useEffect(() => {
options.forEach(...);
setChildrenOptions(children);
}, [selected]);
This is not the cleanest code, but this can be the right direction to solve your very particular issue without knowing much about the rest of the code.