Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.useMemo does not update the data

I am new to hooks. So this might be easy yet I have no idea how to solve:

I have a function like this which takes two arrays columns and data . and those data should be memoized or else it does not work. (recommended by react-table guys)

function ReactTable(props) {

    const columns = React.useMemo(() => props.columns, [])

    const data = React.useMemo(() => props.data, [])

    return <Table columns={columns} data={data} />
}

this works fine but when the props change (say an item is added or removed from data array), the React.useMemo won't send the updated data to the Table component. How can I resolve this :(

like image 354
Amir Shahbabaie Avatar asked Dec 03 '22 17:12

Amir Shahbabaie


2 Answers

This is exactly what the dependency array in hooks is for. You can define variables that 'trigger' the change on hooks. In your case this would mean that you would need to change your code to the following:

function ReactTable(props) {
    const columns = React.useMemo(() => props.columns, [props.columns]);
    const data = React.useMemo(() => props.data, [props.data]);

    return <Table columns={columns} data={data} />
}

This means, whenever props.columns changes, the columns variable is updated and the same for props.data and data.

like image 154
Linschlager Avatar answered Dec 06 '22 11:12

Linschlager


Mind you above answer from user Linschlager might not work if you're using react-table's sorting hook useSortBy. Indeed, the authors final solution did not involve react.useMemo.

To me it worked out anyways. My columns- and row-data came from a query-data object that I had to resolve to fit the specific way react-table does it.

It looked something like this:


function ReportTable({ queryData }) {
... other data such as {selectedPerLevel} ...

 /*                                                                COLUMNS */
  let firstColumn = {
    Header: ' ',
    columns: [
      {
        Header: selectedPerLevel.name,
        accessor: 'perLevel',
      },
    ],
  };

  let otherColumns = [];
  queryData.weeks.forEach((week) => {
    let otherColumn = {
      Header: week,
      Footer: ' ',
      center: true,
      columns: [
        {
          Header: 'Ratio',
          accessor: `ratio${week}`,
        },
        {
          Header: 'Count',
          accessor: 'count' + week,
        },
      ],
    };

    otherColumns = [...otherColumns, otherColumn];
  });

  /*                                                                  ROWS   */
  let listOfRows = queryData.units.map((unit) => {
    let row = {};

    // for each column
    unit.items.forEach(({ week, ratio, count}) => {
      row = {
        ...row,
        ['ratio' + week]: ratio,
        ['count' + week]: count,
      };
    });

    // add the first column-data to the row
    row = { ...row, perLevel: unit.name, id: unit.id };

    return row;
  });

  const data = React.useMemo(() => listOfRows, [queryData]);
  const columns = React.useMemo(() => [{ ...firstColumn }, ...otherColumns], [queryData]);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
  } = useTable({data, columns}, useSortBy);

return <Table .... 

I don't know if this is to anyones help but it all worked out fine for me with above solution.

like image 40
Jammar Avatar answered Dec 06 '22 12:12

Jammar