joy08
joy08

Reputation: 9662

Set state based on an a property present in array of objects : React+Typescript

I want to set state in react based on property that is present in the array of objects.

Code Sandbox that looks similar : https://codesandbox.io/s/sleepy-lamarr-0sbdz

This submit function is present as submitSelection() inside SelectComponent.tsx where I have console logged the state in the question . It is identical

I have a state object that looks this like this:

this state = {
               columns : [
                          {Header: ƒ, accessor: "firstName",show: true},
                          {Header: ƒ, accessor: "status", show: true},
                          {Header: ƒ, accessor: "visits", show: true}
                         ]
             }

I have list of checkboxes that displays column names and based on the "show" flag I hide/show them. I create one more of array of objects based on checkboxes selection that something looks like:

this.state = { 
              selectedOptions: [
                                {name: "firstName", value: "firstName", show: true},
                                {name: "status", value: "status", show: false},
                                {name: "visits", value: "visits", show: true}
                                ]
            } 

Now I need to set the state of "columns" based on the value of "selectedOptions". I have to iterate through the "selectedOptions" array and then based on "value"(here I am using it as key) of each object, I need to update the corresponding "show" property of an object in the "columns".

In this example the columns array should look like after setstate :


columns : [
            {Header: ƒ, accessor: "firstName",show: true},
            {Header: ƒ, accessor: "status", show: false}, // because the value for this in selectedOptions is true
            {Header: ƒ, accessor: "visits", show: true}
          ]


I used the following approach, but it did not work


checkboxSubmit = () => {
   let { selectedOptions , columns } = this.state;
    const updatedObj = columns.map(object =>
      value.some(columns => columns.value === object.accessor)
        ? { ...object, show: columns.show  }
        : { ...object }
    );
    this.setState(columns: updatedObj);
}

Upvotes: 0

Views: 2026

Answers (3)

Jake Luby
Jake Luby

Reputation: 1758

I'd make a map from selectedOptions let selectedOptionsMap = new Map(selectedOptions.map(option => [option.value, option]))

Then update your function to:

checkboxSubmit = () => {
   let { selectedOptions , columns } = this.state;
   let selectedOptionsMap = new Map(selectedOptions.map(option => [option.value, option]))
    const updatedColumns = columns.map(column => (
      {...column, show: selectedOptionsMap.get(column.accessor) ? selectedOptionsMap.get(column.accessor).show : column.show}
    ))
    this.setState(columns: updatedColumns)
}

If you need the map for other calcs you can add it to the state.

ETA: Based on your code sandbox, here's the code for that function

  submitSelection = () => {
    let showMap = new Map(this.state.optionsArr.map(option => [option.value, option.show]))
    let updatedColumns = this.props.data.map(column => (
      {...column, show: showMap.get(column.accessor) != null ? showMap.get(column.accessor) : column.show }
    ))
    this.props.handleSetState(updatedColumns)
  };

Upvotes: 1

Niilo Keinänen
Niilo Keinänen

Reputation: 2582

Here's my solution.

Instead of using a CheckBox data-structure Array in SelectComponent, I used a mapped Array of booleans (just for the show values) - this is just my preference.

I think your previous problems were because you were passing the same Array instance to submitSelection. React doesn't understand that App should be updated, because only the objects inside the Array have been changed, instead of the actual Array.

You could probably get it to work by just recreating the Array before submitting, but in this case you'd be mutating the values of App.columns in SelectComponent. As you know, props aren't supposed to be modified, so this is bad.

Upvotes: 1

Ace
Ace

Reputation: 1146

I think you may have confused your variables while mapping. Try this.

checkboxSubmit = () => {
  this.setState(({columns, selectedOptions}) => {
    const result = columns.map(col => {
      const op = selectedOptions.find(op => col.accessor === op.value);
      return { ...col, show: op.show }
    });
    return result;
  });
});

Upvotes: -1

Related Questions