6

I use getServerSideProps to fetch the initial articles data like this:

export const getServerSideProps = async () => {
  const url =
    "https://conduit.productionready.io/api/articles?limit=10&offset=0";
  const res = await fetch(url);
  const resJson = await res.json();

  return {
    props: {
      data: resJson.articles
    }
  };
};

I need to update articles when page change,so I have the codes below:

export default function IndexPage(props) {
  const { data } = props;
  const [articles, setArticles] = useState(data);
  const [page, setPage] = useState(0);

  useEffect(() => {
    const fetchData = async (page) => {
      const url = `https://conduit.productionready.io/api/articles?limit=10&offset=${page}`;
      const res = await fetch(url);
      const resJson = await res.json();
      setArticles(resJson.articles);
    };

    fetchData(page);
  }, [page]);

  //....
}

Then the question comes:

  1. When your request this page directly, getServerSideProps runs on server-side and fetchs articles. But on client-side, fetchData in the useEffects would also run to fech the same articles again, which is redundant and a bit duplicated.
  2. When transition to the IndexPage from another page through client-side route, there are also two requests for the same articles data: one request is sent to run getServerSideProps on server-side, the other is sent by fetchData. Again, redundant request for same data.

The complete demo is here

I think this is not an unusual situtation. I have seached a lot, but unfortunately, I haven't found any appropriate solutions. Does anyone encounter the same situation or know the best practice to handle it ?

Jason Xu
  • 845
  • 8
  • 22
  • 3
    I think you have to decide here what strategy you have to follow? either to render component at server side or client side. Based on that u have to use getServerSideProps or useEffect https://nextjs.org/docs/basic-features/data-fetching – Shubham J. Jul 23 '21 at 12:16

2 Answers2

0

Maybe the answer will be relevant to someone.

In your case, everything works correctly,because the useEffect in the middle of the page component will always be played, since this is the usual logic of React, it sees that the IndexPage component is new and acts as with the usual mounting rule in React, running all the effects declared by you, in your case it was necessary move the fetching function to the click event handler:

const fetchData = async (page) => {
  const url = `https://conduit.productionready.io/api/articles?limit=10&offset=${page}`;
  const res = await fetch(url);

  return await res.json();
};

const handleClick = async (page) => {
  const nextPage = page >= 0 ? page : 0;
  const data = await fetchData(nextPage);

  setPage(nextPage);
  setArticles(data.articles);
};

return (
  ...
  <button onClick={() => handleClick(page - 1)}>Previous Page</button>
  <button onClick={() => handleClick(page + 1)}>Next Page</button>
  ...
)

The full example is linked here.

But maybe people who come across this question are looking for an answer to the fact that nextjs performs all useEffect and does not work as a SPA in this case, you can read about how to design the layout so that nextjs wraps it as a SPA by following the link here. Or according to my story about how to design next18-next with SPA layout at the link here.

UKRman
  • 404
  • 3
  • 16
-1

You can try using react-query with initial data property: https://tanstack.com/query/v4/docs/react/guides/initial-query-data