React.useMemo does not update the data
Asked Answered
T

2

11

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 :(

Twoway answered 27/2, 2020 at 14:29 Comment(0)
A
23

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.

Angelika answered 27/2, 2020 at 14:40 Comment(6)
the problem I think is with the react-table. either the sort works or update. If I send an empty array it doesn't update but sort works fine. If I send the array, update works but it does not sort the table :) LOLTwoway
Would you mind providing a bit more context, maybe even a small codesandbox that would allow us to actually replicate the issue and find a solution for your specific problem?Angelika
Solved. Thanks. You saved me. I owe you big time!! Here's the sandbox codesandbox.io/s/stupefied-frog-bwhxlTwoway
While this works, why even memoize in the first place? Just pass the props.columns and props.data directly to the Table component, it's the same thing in this case.Kofu
As @SpencerWood wrote, this example memoizes for no reason at all. The memoization should happen at the origin of those two props (some other component which then renders ReactTable), which is not clear from OPs snippet.Primp
@Primp while you are of course correct. But my goal was to address the immediate problem that OP faced. It's very much possible that there is a better solution, looking at the grand scheme of things, yet it's not feasible to fix all of those when looking solely at this small code snippet, nor is it asked for.Angelika
K
1

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.

Kettledrummer answered 30/11, 2020 at 16:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.