Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to set state in a function

So I was trying to build a server side pagination that works like a static one and I'm almost there, But I've encountered some issues which I cannot seem to solve.

This is what my code looks like

const LiveIndex = (props) => {
  const [currentPage, setCurrentPage] = useState(0);
  const [isLoading, setLoading] = useState(false);
  const startLoading = () => setLoading(true);
  const stopLoading = () => setLoading(false);

  useEffect(() => {
    //After the component is mounted set router event handlers

    Router.events.on("routeChangeStart", startLoading);
    Router.events.on("routeChangeComplete", stopLoading);

    return () => {
      Router.events.off("routeChangeStart", startLoading);
      Router.events.off("routeChangeComplete", stopLoading);
    };
  }, []);

  const paginationHandler = (page) => {
    const currentPath = props.router.pathname;
    const currentQuery = props.router.query;
    currentQuery.page = currentPage + 1;

    props.router.push({
      pathname: currentPath,
      query: currentQuery,
    });
    setCurrentPage(currentQuery.page);
  };

  const backToLastPage = (page) => {
    const currentPath = props.router.pathname;
    const currentQuery = props.router.query;

    currentQuery.page = currentPage - 1;
    setCurrentPage(currentQuery.page); // THE code that breaks my code.

    props.router.push({
      pathname: currentPathh,
      query: currentQueryy,
    });
  };

  let content;
  if (isLoading) {
    content = (
      <div>
        <h2 class="loading-text">loading.</h2>
      </div>
    );
  } else {
    //Generating posts list

    content = (
      <div className="container">
        <h2> Live Games - </h2>

        <div className="columns is-multiline">
          <p>{props.games.name}</p>
        </div>
      </div>
    );
  }

  return (
    <>
      <div className={"container-md"}>
        <div>{content}</div>

        {props.games.length ? (
          <a onClick={() => paginationHandler(currentPage)}> moore </a>
        ) : (
          backToLastPage(currentPage)
        )}
      </div>
    </>
  );
};

export async function getServerSideProps({ query }) {
  const page = query.page || 1; //if page empty we request the first page
  const response = await fetch(
    `exampleapi.com?sort=&page=${page}&per_page=10&token`
  );

  const data = await response.json();
  return {
    props: {
      games: data,
    },
  };
}

export default withRouter(LiveIndex);

The issue is my backToLastPage does the job well but I'm unable to use setCurrentPage() in that function, Every time I use that I get the following error

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

How can I possibly update the value of my currentPage state in the backToLast function

Thank you

like image 217
Kentrell Jr Avatar asked Feb 07 '26 22:02

Kentrell Jr


1 Answers

You're calling backToLastPage directly in JSX which will be re-rendered/re-called every time. And setCurrentPage (with useState) triggers re-rendering for state changes in backToLastPage.

You can imagine that every time the state changes, your component gets rendered and it will set states again that make infinite renderings for the component.

You can use useEffect to handle props.games changes. That will help you to trigger backToLastPage only once whenever props.games get changed.

React.useEffect(() => {
   if(!props.games || !props.games.length) {
      backToLastPage(currentPage)
   }
},[props.games])

Full modification can be

const LiveIndex = (props) => {
  const [currentPage, setCurrentPage] = useState(0);
  const [isLoading, setLoading] = useState(false);
  const startLoading = () => setLoading(true);
  const stopLoading = () => setLoading(false);

  useEffect(() => {
    //After the component is mounted set router event handlers

    Router.events.on("routeChangeStart", startLoading);
    Router.events.on("routeChangeComplete", stopLoading);

    return () => {
      Router.events.off("routeChangeStart", startLoading);
      Router.events.off("routeChangeComplete", stopLoading);
    };
  }, []);

  //The main change is here
  //It will be triggered whenever `props.games` gets updated
  React.useEffect(() => {
    if(!props.games || !props.games.length) {
      backToLastPage(currentPage)
    }
  },[props.games])

  const paginationHandler = (page) => {
    const currentPath = props.router.pathname;
    const currentQuery = props.router.query;
    currentQuery.page = currentPage + 1;

    props.router.push({
      pathname: currentPath,
      query: currentQuery,
    });
    setCurrentPage(currentQuery.page);
  };

  const backToLastPage = (page) => {
    const currentPath = props.router.pathname;
    const currentQuery = props.router.query;

    currentQuery.page = currentPage - 1;
    setCurrentPage(currentQuery.page); // THE code that breaks my code.

    props.router.push({
      pathname: currentPathh,
      query: currentQueryy,
    });
  };

  let content;
  if (isLoading) {
    content = (
      <div>
        <h2 class="loading-text">loading.</h2>
      </div>
    );
  } else {
    //Generating posts list

    content = (
      <div className="container">
        <h2> Live Games - </h2>

        <div className="columns is-multiline">
          <p>{props.games.name}</p>
        </div>
      </div>
    );
  }

  return (
    <>
      <div className={"container-md"}>
        <div>{content}</div>

        {props.games.length && (
          <a onClick={() => paginationHandler(currentPage)}> moore </a>
        )}
      </div>
    </>
  );
};

export async function getServerSideProps({ query }) {
  const page = query.page || 1; //if page empty we request the first page
  const response = await fetch(
    `exampleapi.com?sort=&page=${page}&per_page=10&token`
  );

  const data = await response.json();
  return {
    props: {
      games: data,
    },
  };
}

export default withRouter(LiveIndex);
like image 61
Nick Vu Avatar answered Feb 09 '26 12:02

Nick Vu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!