I have a two selection list from where i can select the value
list one= "A", "B"
list two = "C", "D", "E", "F"
I have a state in react
const [filterTags, setFilterTags] = useState({ one: [], two: [] });
I can pass one val at a time from any of the list in updateValue(val)
I need to update the filterTags in such a vay that if its val
is from list one
that is A
or B
it should update the state like this
{one:["A"]: two:[]}
const updateValue = (val) => {
if (val === 'A' || val === 'B') {
setFilterTags({ one: val });
} else {
setFilterTags({ ...filterTags, two: val });
}
};
if I pass A C C D B A E C
one by one it should update the array with the unique values and the output should be
{one:["A"]: two:[]} //passing A
{one:["A"]: two:["C"]} //passing C
{one:["A"]: two:["C"]} // same since C is already there in two on passing C
{one:["A"]: two:["C","D"]} //passing D
{one:["A","B"]: two:["C","D"]} //passing B
{one:["A","B"]: two:["C","D"]} //same since A is already present in one on //passing A
{one:["A","B"]: two:["C","D","E"]} //passing E
{one:["A","B"]: two:["C","D","E"]}// final output on passing C
it should update the respective element with unique values right now the above code can just update a single value
CodePudding user response:
You should make sure that you are only adding elements that are not already there, you can use the includes
function on the arrays to check for that, and you also want to make sure that you are keeping all the previous content.
A potential solution could be to do the following:
const updateValue = (val) => {
if (val === 'A' || val === 'B') {
if(!filterTags.one.includes(val)) {
setFilterTags((prev) => ({ one: [...prev.one, val], two: prev.two }));
}
} else {
if(!filterTags.two.includes(val)) {
setFilterTags((prev) => ({ one: prev.one, two: [...prev.two, val] }));
}
}
};
CodePudding user response:
This commented code can help you:
const updateValue = (val) => {
//creating a temporary copy of filterTags
const tempFilterTags = {...filterTags}
//checking if val is A or B and if finterTag.one does not contain the value
if ((val === 'A' || val === 'B') && filterTags.one.find(el=> el == val) === null) {
//if success, push the value for field one and update filterTag
tempFilterTags.one.push(val)
setFilterTags(tempFilterTags)
}
//checking if val is C, D, E of F and if finterTag.two does not contain the value
if ((val === 'C' || val === 'D' || val === 'E' || val === 'F') && filterTags.two.find(el=> el == val) === null) {
//if success, push the value for field two and update filterTag
tempFilterTags.two.push(val)
setFilterTags(tempFilterTags)
}
};
CodePudding user response:
Use the functional updates option, when setting the state, to get the previous value (prev
), and use spread to create a new state with the previous and updated values. Use a Set to maintain unique values.
const updateValue = (val) => {
if (val === 'A' || val === 'B') {
setFilterTags(prev => ({ ...prev, one: [...new Set([...prev.one, val])] }));
} else {
setFilterTags(prev => ({ ...prev, two: [...new Set([...prev.two, val])] }));
}
};
How there is too much code repetition here, since the logic for setting the state is identical, and just the key changes, so you can refactor it:
const updateValue = (val) => {
const key = val === 'A' || val === 'B' ? 'one' : 'two';
setFilterTags(prev => ({ ...prev, [key]: [...new Set([...prev[key], val])] }));
};
You can also use Array.includes
as suggested by Houssam to avoid updating the state:
const updateValue = (val) => {
const key = val === 'A' || val === 'B' ? 'one' : 'two';
setFilterTags(prev => {
const key = val === 'A' || val === 'B' ? 'one' : 'two';
return prev[key].includes(val)
? prev
: { ...prev, [key]: [...prev[key], val] };
});
};