Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-rendering Table component when parent passes new or updated data

I am transitioning from React Table 6 to 7, which comes with a lot of new changes as React Table 7 is now a headless utility library, built with lots and lots of hooks. This is much different from React Table 6. I am not too familiar with hooks, and haven't used them previously (I had read up on them a few months back), but am now sort of forced to get into the weeds of them, as my application relies heavily on this library.

Using the examples guide here, I am setting up an initial table in my react app, attempting to connect the table to the live data for my app which is fetched with Axios. However, I am struggling right out of the gate with an initial important functionality - having the Table component show / update the data that I am passing to it, but only after that data changes.

To help make clearer, I have created the following component:

import React from 'react';
import { useTable } from 'react-table';

function MyReactTable7Table({ tableData }) {

    // 1. Create Columns
    const columns = React.useMemo(
        () => [
            {
                Header: 'Name',
                columns: [
                    {
                        Header: 'Col Available From Start',
                        accessor: 'conferenceId'
                    },
                    {
                        Header: 'Col Avail After Parent Re-Render',
                        accessor: 'teamMarket'
                    }
                ]
            }
        ],
        []
    );

    // 2. Create Data
    const data = React.useMemo(() => tableData, []);

    // 3. Call Use Table
    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        rows,
        prepareRow
    } = useTable({ columns, data });

    // 4. Return the HTML Table
    return (<>
        <table {...getTableProps()}>
            <thead>
                {headerGroups.map(headerGroup => (
                    <tr {...headerGroup.getHeaderGroupProps()}>
                        {headerGroup.headers.map(column => (
                            // Add the sorting props to control sorting. For this example
                            // we can add them into the header props
                            <th {...column.getHeaderProps()}>
                                {column.render('Header')}
                            </th>
                        ))}
                    </tr>
                ))}
            </thead>
            <tbody {...getTableBodyProps()}>
                {rows.map(
                    (row) => {
                        prepareRow(row);
                        return (
                            <tr {...row.getRowProps()}>
                                {row.cells.map(cell => {
                                    return (
                                        <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                                    );
                                })}
                            </tr>
                        );
                    }
                )}
            </tbody>
        </table>
    </>);
}

export default MyReactTable7Table;

This is pretty much copied directly from the example page, except rather than using mock data, I am passing the data that is fetched from the parent component and passed as a prop. Here's the problem though: although the data from the parent component does update (initially, a skinny table with only 5 columns is fetched, and then a larger table with 20 columns is fetched that replaces the first table in the parent components state), the UI doesn't update on my web app. (I think because the table component's internal state is not updating?)

Im my example, conferenceId is 1 of the initial 5 columns fetched, however teamMarket is one of the 20 but not one of the 5 initial columns. Although the parent component fetches the new data and rerenders, the Table Component does not update to show the new data in the new column.

I am figuring out hooks and headless components on the fly with this, and would like to follow best practices with using this library, because from the docs + examples, it seems like a very good and powerful table component for React.

Edit

To update and clarify quickly, maybe it is a bad pattern for the parent component to fire off 2 separate async Axios fetches to update the same parent state variable. I'm not sure. As I mentioned, and just to clarify, the 1st fetch quickly grabs a skinny version of the data, while the 2nd fetch grabs the full table. Because the parent state updates with the new data array, the array being passed as the tableData prop to <MyReactTable7Table /> changes as well.

It's tough to hook up live, because the bug / issue itself is related to the live data not updating correctly...

like image 725
Canovice Avatar asked Apr 17 '20 04:04

Canovice


People also ask

Which method cause re-rendering of a component whenever any data change happens in the component in React?

1. Re-render component when state changes. Any time a React component state has changed, React has to run the render() method.

What causes a component to re-render?

React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.

Does child component Rerender on parent state change?

State changes in Child component doesn't effect on the parent component, but when a state of parent component changes all the child components render.

How do you prevent components from rendering after state change?

1. Memoization using useMemo() and UseCallback() Hooks. Memoization enables your code to re-render components only if there's a change in the props. With this technique, developers can avoid unnecessary renderings and reduce the computational load in applications.

How to prevent react child components from re-rendering?

Wrap your children in React.memo (), this way every time one of your children updates a state in the Parent component, all the children that don't care and don't receive that updated state as a prop, won't re-render. Use a global state manager ( Suggested ).

Is it possible to update data from a child component?

Still, it can be useful to update and manipulate data from a Child component, especially when Redux is involved. React is probably performs shallow comparisons, and might not re-render even though the state is clearly changing. As a workaround, you can do this in mapStateToProps:

Why doesn't the Redux-store re-render when the child component updates?

The redux-store is updated properly, but the child component doesn't re-render. It's normally not the responsibility of the Child to fill the data. Instead, it should receive data that's already been prepared by the Parent.

How do I pass props from parent component to child component?

The parent component passes some props to the child component. When the child component receives those props, it should call some Redux action which changes some of the props that were passed from the parent asynchronously. Here are the two components:


1 Answers

You have provided an empty array dependency to your useMemo which means that the memoized value of tableData is created and assigned to data and is never changed. You will need to provide dependency indicating when the useMemo should recalculate/regenerate the value.

In your case, there is no need of 2nd useMemo.

So remove below code and just use tableData

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

Like this:

const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        rows,
        prepareRow
    } = useTable({ columns, data: tableData });
like image 135
gdh Avatar answered Oct 18 '22 13:10

gdh