0

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

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks much @Niilo. There any approach without mutating the props? It would really be helpful:)
In my solution, I use Object.assign to create copies of the props. This works, but it should be noted that the properties of the props are NOT copied deeply, only by reference! So, if one of the properties is an object, say { something: number }, and you modify this objects property in the copied object, it will carry over to the original one. In some cases, this might be a problem but your data-structures don't seem to contain any non-primitive types so should be fine.
Init state to same as in constructor: this.setState({ optionsArr: this.props.data.map(option => option.show) });
1

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

3 Comments

This did not work. codesandbox.io/s/sleepy-lamarr-0sbdz . Here is the link to the sandbox. This submit function is present as submitSelection() inside SelectComponent.tsx where I have console logged the state in the question . It is identical
@vrosario I've updated my answer to include the code from your code sandbox
You'll need to save it in the state to preserve it through the rendering process
-1

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

1 Comment

This did not work. codesandbox.io/s/sleepy-lamarr-0sbdz . Here is the link to the sandbox. This submit function is present as submitSelection() inside SelectComponent.tsx where I have console logged the state in the question . It is identical

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.