Andrew H
Andrew H

Reputation: 463

Functional component data table not rerendering when add/remove columns which is set/stored in state in an array of objects

I am building a datatable and have added a checkbox dropdown for adding/removing columns in the table. Everything works fine except it is not rerendering the table until I click on one of the header titles.

At the top of the function component, I am setting the state as follows:

  const [formColumns, setDisplayFields] = useState(formFields);

formFields is retrieved from a file and is formatted as below. It's an array of JSON column objects that looks like this:

    [id: {
      name: 'id',
      label: 'Patient Id',
      displayColumn: false,
      displayOrder: 1,
    },
    firstName: {
      name: 'firstName',
      label: 'First Name*',
      requiredErrorMsg: 'First name is required',
      displayColumn: true,
      displayOrder: 2,
    },
    middleName: {
      name: 'middleName',
      label: 'Middle Name',
      displayColumn: false,
      displayOrder: 0,
    },
    lastName: {
      name: 'lastName',
      label: 'Last Name*',
      requiredErrorMsg: 'Last name is required',
      displayColumn: true,
      displayOrder: 0,
    },
    suffix: {
      name: 'suffix',
      label: 'Suffix',
      displayColumn: false,
      displayOrder: 0,
    },
    dob: {
      name: 'dob',
      label: 'Date of Birth*',
      requiredErrorMsg: 'Birth date is required',
      invalidErrorMsg: 'This is not a valid date',
      displayColumn: true,
      displayOrder: 3,
    },
    organization: {
      name: 'organization',
      label: 'Organization',
      displayColumn: false,
      displayOrder: 4,
    },
  ]

There are actually more columns, but this should suffice for describing what I'm doing. The 'displayColumn' element is changed in an onChange event in the same component that displays the table (passes it as a prop into checkbox menu). Here's the onchange:

  /**
   * handleCheckboxSelect
   * @param {string} colname
   */
  var handleCheckboxSelect = (colname) =>
  {
    //return the index of the column checked/unchecked
    var icol = getColumnIndex(formColumns, colname);
    console.log('FOUND COLINDEX = ' + icol + '.');
    if (icol > -1) {
      //toggle the display parameter
      formColumns[icol].displayColumn = (formColumns[icol].displayColumn === false);
      //store the updated column in the column list
      setDisplayFields(formColumns);
    }
    else {
      console.log('checkbox colname = ' + colname);
    }
  }

As you can see, I am using state as required, and any time state changes, it should force a re-render. However, it's not. Is it because I am using an array of objects? If I pass a single column back and stroe that in state, would that fix the issue? I'm stumped. Any help would be greatly appreciated!

Upvotes: 0

Views: 431

Answers (1)

Arpitha Chandrashekara
Arpitha Chandrashekara

Reputation: 1147

You are setting same formColumns reference on setDisplayFields which will not trigger re-render of the component. Try to copy formColumns to a new array and make changes on that array.

Try this -

var handleCheckboxSelect = (colname) =>
  {
    //create new array from existing one
    let newColumns = [...formColumns];

    var icol = getColumnIndex(newColumns, colname);
    console.log('FOUND COLINDEX = ' + icol + '.');
    if (icol > -1) {
      //toggle the display parameter
      newColumns[icol].displayColumn = (newColumns[icol].displayColumn === false);
      //store the updated column in the column list
      setDisplayFields(newColumns);
    }
    else {
      console.log('checkbox colname = ' + colname);
    }
  }

Upvotes: 1

Related Questions