Dejan.S
Dejan.S

Reputation: 19138

How to solve a function call that uses useState with getting "Too many re-renders. React...."

Context:
I'm using React hooks. What I'm doing is a onClick={sortTable(valuePassed)} and check a state value and change it with setSortedKey() and setSortedOrder()


Error:

"Too many re-renders. React limits the number of renders to prevent an infinite loop."

From what I understand useState and setMyState will re-render the component each time it's called. My issue in this particular situation is I know that I should use useEffect() but fail to understand how to do it with this type of function.


My component:
The component looks like this.

function BaseTable(props) {
  // fake data
  const headers = []

  // state
  const [sortedKey, setSortedKey] = useState('')
  const [sortedOrder, setSortedOrder] = useState('')

  // methods
  const sortTable = (sortKey) => {
    setSortedOrder(sortedKey !== sortKey ? '' : sortedOrder)
    setSortedKey(sortedKey !== sortKey ? '' : sortedKey)

    setSortedOrder(sortedOrder === 'asc' ? 'desc' : 'asc')
  }

  return (
    <table className={ classnames('table', { 'table--layout-fixed': props.fixedLayout }) }>
    <thead>
      <tr className="table__header-row">
        {headers.map((header, index) =>
          <th key={ index } className="table__header-cell">
            <button onClick={ sortTable(header.sortKey) }>
                { header.displayName }

              <div className="table__header-sort-actions">
                <ArrowDownSorting className="table__header-sort" />
                <ArrowDownSorting className="table__header-sort" />
              </div>
            </button>
          </th>
        )}
      </tr>
    </thead>
    <tbody>
      {props.tableData.map((row) =>
        <tr className="table__body-row" key={row.name + row.i}>
          <TableCellBasic cellValue={row._id} />
          <TableCellBasic cellValue={row.prop1} />
          <TableCellBasic cellValue={row.prop2} />
          <TableCellBasic cellValue={row.prop3} />
        </tr>
      )}
    </tbody>
  </table>
  )
}

BaseTable.propTypes = {
  header: PropTypes.array,
  tableData: PropTypes.array,
  tableName: PropTypes.string,
  fixedLayout: PropTypes.bool,
  defaultSortedKey: PropTypes.string
}

export default BaseTable

Upvotes: 0

Views: 75

Answers (2)

wkgalla
wkgalla

Reputation: 256

You should pass a callback to onClick prop

onClick={() => sortTable(header.sortKey)}

Upvotes: 0

Andy
Andy

Reputation: 63524

At the moment you're assigning the value of the call to sortTable to the handler.

<button onClick={ sortTable(header.sortKey) }>

You need to assign a function instead:

<button onClick={() => sortTable(header.sortKey)}>

Upvotes: 1

Related Questions