简体   繁体   中英

Too many re-renders with React Hooks and Redux

I have a component that displays a list of Cards. I'm trying to sort the table rows but running into some issues. When i go to the page i'm getting the following error:

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

and it's pointing to this line

setData(_.sortBy(filteredData.reverse()));

here's my full component code. can anyone see a problem with what I'm trying to do?

import React, { useState } from "react";
import Search from "./Search";
import TimeAgo from "react-timeago";
import { useSelector, useDispatch, connect } from "react-redux";
import { Table } from "semantic-ui-react";
import { searchChange } from "../reducers/searchReducer";
import _ from "lodash";
// import { useField } from "../hooks";

const searchCards = ({ baseball, search }) => {
  return search
    ? baseball.filter(a =>
        a.title[0].toLowerCase().includes(search.toLowerCase())
      )
    : baseball;
};

const Cards = props => {
  const [column, setColumn] = useState(null);
  const [direction, setDirection] = useState(null);
  const [filteredData, setData] = useState(props.cardsToShow);

  const handleSort = clickedColumn => {
    if (column !== clickedColumn) {
      setColumn(clickedColumn);
      setData(_.sortBy(filteredData, [clickedColumn]));
      setDirection("ascending");
      return;
    }

    setData(_.sortBy(filteredData.reverse()));
    direction === "ascending"
      ? setDirection("descending")
      : setDirection("ascending");
  };

  return (
    <>
      <div>
        <Search />
        <h3>Vintage Card Search</h3>
        <Table sortable celled fixed striped>
          <Table.Header>
            <Table.Row>
              <Table.HeaderCell
                sorted={column === "title" ? direction : null}
                onClick={handleSort("title")}
              >
                Card Title
              </Table.HeaderCell>
              <Table.HeaderCell># Bids</Table.HeaderCell>
              <Table.HeaderCell>Watchers</Table.HeaderCell>
              <Table.HeaderCell>Price</Table.HeaderCell>
              <Table.HeaderCell>Time Left</Table.HeaderCell>
            </Table.Row>
          </Table.Header>
          <Table.Body>
            {props.cardsToShow.map(card => (
              <>
                <Table.Row key={card.id}>
                  <Table.Cell>{card.title}</Table.Cell>
                  <Table.Cell>
                    {card.sellingStatus[0].bidCount
                      ? card.sellingStatus[0].bidCount
                      : 0}
                  </Table.Cell>
                  <Table.Cell>
                    {card.listingInfo[0].watchCount
                      ? card.listingInfo[0].watchCount
                      : 0}
                  </Table.Cell>
                  <Table.Cell>
                    $
                    {card.sellingStatus &&
                      card.sellingStatus[0].currentPrice[0]["__value__"]}
                  </Table.Cell>
                  <Table.Cell>
                    <TimeAgo
                      date={new Date(
                        card.listingInfo && card.listingInfo[0].endTime
                      ).toLocaleDateString()}
                    />
                  </Table.Cell>
                </Table.Row>
              </>
            ))}
          </Table.Body>
        </Table>
      </div>
    </>
  );
};

const mapStateToProps = state => {
  return {
    baseball: state.baseball,
    search: state.search,
    cardsToShow: searchCards(state)
  };
};

const mapDispatchToProps = {
  searchChange
};

export default connect(mapStateToProps, mapDispatchToProps)(Cards);
// export default Cards;

Yachaka has already pointed out the incorrect line, but their answer doesn't explain what the issue is.

When you pass props in React with prop={expression} , the expression in the brackets gets evaluated, much like function arguments are evaluated when they are passed. Hence, whenever the component is rendered, handleSort("title") is called. This function then causes the props to be updated, and the component is re-rendered, causing the cycle to repeat indefinitely.

So the problem is that, instead of passing a function that should be called when the button is clicked, you call that function (with handleSort("title") ), which results in undefined , and causes a feedback loop.

Instead you should use an expression that returns a function. The most concise way of doing that in JavaScript is an arrow function, as Yachaka mentioned () => handleSort("title") . This evaluates to a function that calls handleSort .

Change this line:

onClick={handleSort("title")}

by

onClick={() => handleSort("title")}

EDIT: Reinis has written a nice explanation below!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM