最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Too many re-renders with React Hooks and Redux - Stack Overflow

programmeradmin0浏览0评论

I have a ponent 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 ponent 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;

I have a ponent 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 ponent 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;
Share Improve this question asked Nov 23, 2019 at 22:53 John RogersonJohn Rogerson 1,1933 gold badges22 silver badges53 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

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 ponent is rendered, handleSort("title") is called. This function then causes the props to be updated, and the ponent 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!

发布评论

评论列表(0)

  1. 暂无评论