Mohammad Zubair
Mohammad Zubair

Reputation: 413

Update an array inside an object with unique value in react with hook

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

Upvotes: 2

Views: 663

Answers (3)

Ori Drori
Ori Drori

Reputation: 191976

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] };
  });
};

Upvotes: 0

Elson Ramos
Elson Ramos

Reputation: 820

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)
  } 
};

Upvotes: 0

Houssam
Houssam

Reputation: 1877

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] }));
    }
  }
};

Upvotes: 2

Related Questions