Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting Maximun call stack In production. #1739

Closed
pavittars opened this issue Dec 9, 2019 · 20 comments
Closed

Getting Maximun call stack In production. #1739

pavittars opened this issue Dec 9, 2019 · 20 comments

Comments

@pavittars
Copy link

pavittars commented Dec 9, 2019

I'm getting maximum call stack in production but during dev, it's working fine. Follow is the code I'm using.

import React, { useEffect } from 'react';
import { useTable, usePagination, useSortBy, useRowSelect } from 'react-table';
import Arrow from '../../assets/img/arrow.png';
import SortArrow from '../../assets/img/downarrow.png';
export default function Table({ columns = [], data = [], _setSelected }) {

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    // rows,
    prepareRow,
    pageOptions,
    page,
    state: { pageIndex, selectedRowPaths },
    previousPage,
    nextPage,
    canPreviousPage,
    canNextPage,
    selectedFlatRows
  } = useTable(
    {
      columns,
      data,
      disableSortRemove: true,
    },
    useSortBy,
    useRowSelect,
    usePagination
  );

  useEffect(
    () => {
      _setSelected(selectedFlatRows);
    },
    [selectedRowPaths, selectedFlatRows]
  );

  return (
    <>
      <div className="table-responsive">
        <table
          {...getTableProps()}
          className="w-100 table table-bordered table-striped table-hover"
        >
          <thead>
            {headerGroups.map((headerGroup) => (
              <tr {...headerGroup.getHeaderGroupProps()}>
                {headerGroup.headers.map((column) => (
                  <th scope="col" {...column.getHeaderProps(column.getSortByToggleProps())}>
                    {column.render('Header')}
                    {column.isSorted && <img src={SortArrow} width="18" className={column.isSortedDesc?'':'rotate-up'} alt="sorting" />}
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody {...getTableBodyProps()}>
            {page.map((row, i) => {
              prepareRow(row);

              return (
                <tr {...row.getRowProps()}>
                  {row.cells.map((cell) => {
                    return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>;
                  })}
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
            {data.length > 10 && <>
      <div className="text-center">
        Page{' '}
        <em>
          {pageIndex + 1} of {pageOptions.length}
        </em>
      </div>
      <div className="text-center">
        <button
          className="btn btn-primary"
          onClick={() => previousPage()}
          disabled={!canPreviousPage}
        >
          <img src={Arrow} className="previous-arrow" alt="Previous" />
        </button>
        <button
          className="btn btn-primary"
          onClick={() => nextPage()}
          disabled={!canNextPage}
        >
          <img src={Arrow} className="next-arrow" alt="Next" />
        </button>
      </div>
      </>}
    </>
  );
}
@tannerlinsley
Copy link
Collaborator

Are you using the latest release candidate version?

@pavittars
Copy link
Author

@tannerlinsley i'm using "react-table": "^7.0.0-rc.6" this version.

@tannerlinsley
Copy link
Collaborator

Comment out the effect. Does it still happen?

@pavittars
Copy link
Author

After commenting the effect works it's fine.

@tannerlinsley
Copy link
Collaborator

That is strange. useEffect should not be running in an SSR environment. What are you building your app in? Next?

@pavittars
Copy link
Author

I'm using Reactjs

@tannerlinsley
Copy link
Collaborator

Yes, but how and when are you doing server side rendering?

@pavittars
Copy link
Author

No, we are not doing the SSR. Running the app using the express server.

@tannerlinsley
Copy link
Collaborator

So you are rendering the app html Using express, then using React normally on the client?

@tannerlinsley tannerlinsley changed the title Getting Maximun call stack on the server. Getting Maximun call stack In production. Dec 10, 2019
@tannerlinsley
Copy link
Collaborator

I’ve updated the issue to better reflect the question you’re asking.

@tannerlinsley
Copy link
Collaborator

What’s happening is that your effect is using a dependency that is likely changing from the effect itself. Thus you get an infinite call stack.

@tannerlinsley
Copy link
Collaborator

I think the best thing to do here is to make a codesandbox that illustrates the issue. It will be 100x easier for me to debug from there.

@tannerlinsley
Copy link
Collaborator

Please comment with a codesandbox demonstrating the issue and we can reopen this issue :)

@shiglet
Copy link

shiglet commented Jan 6, 2020

I'm facing a similar issue, I also have a similar code than him.

Something i could add is the _setSelected (named setSelectedRows) function passed in params to his Table component, is setting the state in the parent component. So it causes a rerendering of the Table component which changes selectedFlatRows (maybe ?) so the useEffect is called again so the infinite loop starts again and again.

To solve this issue, i remove the this.setState({selectedRows}) i had in the setSelectedRows (_setSelected equivalent in your code) and replaced it by this.selectedRows = selectedRows. So selectedRows isn't no more part of the state, so it won't call render method of parent component and the table component won't be rerender and causes that infinite loop.

It worked for me because i didn't really need that selectedRows in the parent component state, but what if i really needed it ? How can i solve this ? 'Cause i think i'm gonna soon need it.

EDIT : i'm using "react-table": "^7.0.0-rc.15"

@iAmGhost
Copy link

iAmGhost commented Feb 6, 2020

...
It worked for me because i didn't really need that selectedRows in the parent component state, but what if i really needed it ? How can i solve this ? 'Cause i think i'm gonna soon need it.

EDIT : i'm using "react-table": "^7.0.0-rc.15"

I've found workaround for this issue, insipred by this conversation

First you have to set initialState.selectedRowIds but make sure it's never recreated during render:

const INITIAL_SELECTED_ROW_IDS = {};

const DataTable = ({ data, columns, onSelectedRowChange }) => {
    const {
        getTableProps,
        page,
        prepareRow,
        headerGroups,
        pageCount,
        gotoPage,
        state: { pageIndex, selectedRowIds },  // selectedRowPaths is renamed to selectedRowIds
    } = useTable(
        {
            data,
            columns,
            initialState: {
                pageSize: pageSize,
                selectedRowIds: INITIAL_SELECTED_ROW_IDS  // Do not just use {}
            }
        },

...

and re-implement selectedFlatRows's behavior like this:

import { useMountedLayoutEffect } from "react-table";
...

    useMountedLayoutEffect(() => {
        const selectedIds = Object.keys(selectedRowIds);
        var selectedRowsData = selectedIds
            .map(x => data[x])
            .filter(function(x) {
                return x != null;
            });

        onSelectedRowChange(selectedRowsData);
    }, [onSelectedRowChange, selectedRowIds]);

@vishwa3
Copy link

vishwa3 commented Jul 14, 2020

@iAmGhost : is it mandatory to give initialState for selectedRowIds , beacuse UI will load with pre-selected rows , is there any other way ?

@austincondiff
Copy link

I am running into this issue as well. It runs regardless of whether or not a selection was made.

@duhaime
Copy link

duhaime commented Mar 31, 2022

I hit this same thread and eliminated the infinite rendering by adding autoResetHiddenColumns: false to the useTable call:

const tableInstance = useTable({
  columns,
  data,
  autoResetHiddenColumns: false,    //  <-- stops the rerendering 🥳
}, useSortBy);

@paveltretyakovru
Copy link

It is very strange behavior and it is hint when using react-table select rows feature.
That's work for me:

const tableInstance = useTable({
  columns,
  data,
  autoResetHiddenColumns: false,    //  <-- stops the rerendering 🥳
  autoResetSortBy: false, //  <-- stops the rerendering 🥳
}, useSortBy);

@CatPerry
Copy link

CatPerry commented Jul 9, 2022

None of the above (or anywhere else on the interwebs) worked for me but here's what did. And I imagine, with the number of people who've asked this same question about React Table v7, that in version 8 of React Table, the state, especially state having to do with selection, has been ironed out. But anyway this is the ONLY workaround that worked for me, loosely based on this codesandbox.

// Parent component

  1. I used a useCallback hook to prevent my setSelectedRows (your setSelection) function being passed to the child as a new function and kicking off multiple renders.

  2. And I passed in an initial state that sets React Table's selectedRowIds with the parent's selectedRows:

const ParentDoingParentyThings = () => {
  const [selectedRows, setSelectedRows] = React.useState({});
  const handleSelection = React.useCallback((value) => {
    setSelectedRows(value);   
    }, []); 

return (
  <Table
        data={tableData}
        setSelectedRows={handleSelection}
        initialState={{ sortBy: [{ id: 'totalSeries', desc: true }], selectedRowIds: selectedRows }}
        ...
      />
  )
}

// And the Table / child
Then!...

  1. I use this lesser know function from React Table called useMountedLayoutEffect. Dont ask me in detail what it does, but it works, that's what it does....
  2. Then I pull from RT's selectedRowIds state
  3. And I use RT's useMountedLayoutEffect function like I would a useEffect
import {
  ...
  useMountedLayoutEffect,
} from 'react-table';

export const Table = ({
  data,
  setSelectedRows,
  initialState,
  ...
}: Props) => {
  ...
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state: { selectedRowIds },
  } = useTable(
    {
      data: tableData,
      initialState,
      ...
    },
    useSortBy,
    useRowSelect,
  );

  useMountedLayoutEffect(() => {
    setSelectedRows && setSelectedRows(selectedRowIds);
  }, [setSelectedRows, selectedRowIds]);

  return (
    <table {...getTableProps()} className={className}>
      ...
    </table>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants