无法在函数中设置状态

Unable to set state in a function

所以我试图构建一个像静态分页一样工作的服务器端分页,我快完成了,但是我遇到了一些我似乎无法解决的问题。

这就是我的代码的样子

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);

问题是我的 backToLastPage 很好地完成了工作,但我无法在该函数中使用 setCurrentPage(),每次我使用它时都会收到以下错误

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

我怎样才能在 backToLast 函数

中更新 currentPage 状态的值

谢谢

您在 JSX 中直接调用 backToLastPage,每次都是 re-rendered/re-called。并且 setCurrentPage(与 useState)触发 re-rendering backToLastPage 中的状态变化。

您可以想象,每次状态发生变化时,您的组件都会被渲染,并且它会再次设置状态,从而为组件进行无限渲染。

您可以使用 useEffect 来处理 props.games 更改。这将帮助您在 props.games 发生变化时仅触发一次 backToLastPage

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

完整修改即可

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);