Closed rafaelalmeidatk closed 2 years ago
Hi
I'm working an next js these days and i want to do something cool. when user make http request to my page i (for SEO) i want page render in Server Side and show all data at ones (i want fetch data at Server Side). but when page load completed and user navigate between pages using next/lint
i want data render in Client Side (i want fetch data in Client Side). with getInitialProps
we can do this let me show you an example.
function Index({ posts }) {
const [postsArr, setPostsArr] = useState(posts);
useEffect(() => {
async function fetchNewPosts() {
const res = await fetch("https://getpost.com/");
setPostsArr(await res.json());
}
if (posts.length === 0) {
fetchNewPosts();
}
}, []);
return (
<>
<Nav />
<p>Hello World May I Pick Banana!</p>
<pre>{JSON.stringify(postsArr, null, 4)}</pre>
</>
);
}
Index.getInitialProps = async ({ req }) => {
let posts = [];
if (req) {
const res = await fetch("https://getpost.com/");
posts = await res.json();
}
return { posts };
};
export default Index;
in this approach if there is request we fetch data at first place (Server Side Rendering) but if we navigating to this page with next/link
it fetches data from client side (Client Side Rendering).
But with these new data fetching methods getStaticProps
and getServerSideProps
we cant able to do above behavior.
please fix this issue in new versions.
@sadraromexs
That's exactly what I've done in my previous 2 NextJS projects. Since starting my new project I've taken the official advice and am doing everything using getServerSideProps (because I believe the current model for getStaticProps is totally broken).
My old sites were lightning fast, the new one is significantly slower, because making a trip to the API on every request is obviously going to be slower. Seems like a bad decision.
It's obvious that user should not wait a few seconds in which nothing happens (because getServerSideProps is not finished loading) when he clicks a link. He should see some action is happening, for example:
Just one question, how then you will skip graphql parallel query with router.isFetchingAfterDefer
?
export function Test(): JSX.Element {
const { data, error } = useTestQuery() // will it fire alongside getServerSideProps?
return (
<Main>
{JSON.stringify(data)}
</Main>
)
}
export const getServerSideProps: GetServerSideProps = async () => {
const apolloClient = initializeApollo()
await apolloClient.query({ query: TestQuery })
return {
props: {
initialApolloState: apolloClient.cache.extract(),
},
}
}
Any news on this issue? I'll be developing a project which has similar requirements soon and want to know whether to use getInitialProps
or getServerSideProps
.
Same problem here. Itβs my first NextJS app and Iβm not sure how to handle this situation. Iβm probably going to end up using getInitialProps
despite of being getServerSideProps
the recommended option according to the documentation. Any workaround so far?
Still waiting to see what happens with this. They say that getInitialProps is still going to be supported but it's been heavily demoted in the documentation and my guess is that it will stay there but won't be worked on again (just a guess but seems reasonable).
The trouble is, the more I think about this issues the more I think it's intertwined with other issues do do with Data fetching. GetStaticProps should also work this way (blocking when generating SSG, not blocking when client side navigation) and we hope to see improvements that allow data-fetching at app/path/component level not just page level. All of this is tied together and needs a solution which brings it all together.
My hope would be that Vercel would open up an RFC for people to comment on a new props fetching solution where we can discuss all of these issues on one place and find a single solution. That's ot something for a minor release though.
The solution to this issue is covered by https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html and it's interplay with concurrent mode / suspense. Can't share the exact details yet, will keep you posted.
Any activity on this?
It's really annoying problem!
Very common plugins (next-i18next, next-translate) are already dropped support for getInitialProps
. All new examples are using getServerSideProps
as preffered solution and there is NO WAY to eliminate extra network call every time route changed?
Nobody uses client-side cache? Hmm... don't believe.
Waiting for experimental react feature is not a solution for now.
You really need to think about it. I don't understand why this issue takes so little attention from community...
Any activity on this? It's really annoying problem! Very common plugins (next-i18next, next-translate) are already dropped support for
getInitialProps
. All new examples are usinggetServerSideProps
as preffered solution and there is NO WAY to eliminate extra network call every time route changed? Nobody uses client-side cache? Hmm... don't believe. Waiting for experimental react feature is not a solution for now.You really need to think about it. I don't understand why this issue takes so little attention from community...
FYI, next-i18next
recently release version 8.0 that doesn't add a getInitialProps
on App
anymore.
You really need to think about it. I don't understand why this issue takes so little attention from community...
Couldn't agree with this more.
There should be no server side call on client-side navigation. That should be the default way data-fetching works unless you opt out of it. It's especially annoying seeing as this was possible before (and technically still is if you're prepared to build a new site on deprecated features).
I really hope this feature is added because getServerSideProps is slowing down our site quite tremendously. Language used around getInitialProps makes it seem like it will be deprecated soon, and getStaticProps/Paths just doesn't make sense for our use-case because our pages have a lot of dynamic data, some of which depends on the user.
wow, i didn't realize how fast and convenient NuxtJS async Fetch
until i came to React nextjs!
don't understand why it's so hard to come up with a similar concept.
Language used around getInitialProps makes it seem like it will be deprecated soon
It's not deprecated / will not be deprecated soon. We just recommend getStaticProps
/getServerSideProps
for the majority of use cases.
@timneutkens how does this solve the majority of use cases since serverSideProps
is meant for SSR
but now no one would want to have a slow page load on client-side navigation!
so it's totally unusable for SSR, i know many use cases are towards SSG but i don't think it's as much as people who want to dynamically generate their page, just take a look at Nuxtjs fetching method !!
Language used around getInitialProps makes it seem like it will be deprecated soon
It's not deprecated / will not be deprecated soon. We just recommend
getStaticProps
/getServerSideProps
for the majority of use cases.
Noted. That's good because we changed our implementation over to getInitialProps()
and now our site is tremendously faster AND we're getting the SEO optimizations we need. I do have trouble seeing many use cases for getServerSideProps() given how slow it is, so I hope there's more clarity provided on this at some point.
Language used around getInitialProps makes it seem like it will be deprecated soon
It's not deprecated / will not be deprecated soon. We just recommend
getStaticProps
/getServerSideProps
for the majority of use cases.Noted. That's good because we changed our implementation over to
getInitialProps()
and now our site is tremendously faster AND we're getting the SEO optimizations we need. I do have trouble seeing many use cases for getServerSideProps() given how slow it is, so I hope there's more clarity provided on this at some point.
I've found getServerSideProps
to work well when used with plain <a>
elements. getServerSideProps
feels particularly slow when used with Next.js's <Link>
component since there's no indication to the user that the browser is fetching data when they clicked on a <Link>
.
A good use case for getServerSideProps
is if you're importing heavy NPM dependencies that you don't want to include in the client bundle. AFAIK getInitialProps
can't do that.
You'll miss out on the automatic prefetching if you just use <a>
elements, but I suppose it'd be possible to build a custom <ServerSideLink to="/about">
component that uses IntersectionObserver
to detect when it is in view and calls router.prefetch(to)
to prefetch the static assets without and without doing client-side navigation. I haven't actually tried this though. Maybe it's a bad idea. π€·π»
Hello everyone π
I was facing this problem in my project and I ended up using this as a workaround (hacky as hell but seems to work):
const isServerReq = req => !req.url.startsWith('/_next');
function Post({ post }) {
// Render post...
}
export async function getServerSideProps({ req }) {
const initData = isServerReq(req) ? await fetch(...) : null;
return {
props: {
initData,
},
}
}
Thanks god I found this thread..
I'm using NextJS since the beginning (> 3yr) and always upgraded with the new versions to get the new features. I'm using other libraries like next-routes, next-redux-wrapper, next-i18next and I cannot upgrade all of them anymore.
I did all the work to migrate from getInitialProps to getServerSideProps for my SaaS and getStaticProps for the website but the result is just not what I was expecting. The fact that getServerSideProps is called on every client side routing is just a no go.
At the end I felt like NextJS was just a nice solution for e-commerce and blogs but was not the solution to create a complex app because the current 3 methods (SSR/Path/Static) just don't answer the issue that getInitialProps alone was doing perfectly. I would prefer focusing on my features instead of reading all the possible discussions (GitHub/SO/Reddit) to find workarounds that should be normal behaviour (or at least fallback).
Because of the doc, the other libraries are just like "getInitialProps will be removed soon so we will just stop supporting it at all now" (from the libraries owners).
It's really annoying because we really want to migrate and get the new features but since v10 we got some regressions related to general use cases so we cannot fully enjoy the optimizations or update others libraries.
I'll keep getInitialProps for now but I'll also keep my refactor branch active, waiting for news about a real SSR.
I'm sure you have everything in the NextJS core to do something great though. Please don't only focus on blog/e-commerce, there are plenty of great/complex app that need the most advanced features of SSR! π
Language used around getInitialProps makes it seem like it will be deprecated soon
It's not deprecated / will not be deprecated soon. We just recommend
getStaticProps
/getServerSideProps
for the majority of use cases.
That's good to know. But I think we'd all be interested to know why you're pushing the slower, less efficient new way of doing things for "the majority of use cases" when the old way is much faster? What benefit do we get from doing a server side call on every client-side navigation? Isn't there a way of changing it to get the best of both worlds?
It seems that the team are quite dismissive of people's concerns over this and maybe don't understand the problem?
Hello everyone π
I was facing this problem in my project and I ended up using this as a workaround (hacky as hell but seems to work):
const isServerReq = req => !req.url.startsWith('/_next'); function Post({ post }) { // Render post... } export async function getServerSideProps({ req }) { const initData = isServerReq(req) ? await fetch(...) : null; return { props: { initData, }, } }
Based on this reply, I've come up with a high order function to handle this in a more elegant way:
/**
* Do not SSR the page when navigating.
* Has to be added right before the final getServerSideProps function
*/
export const hasNavigationCSR = (next?: GetServerSideProps) => async (
ctx: GetServerSidePropsContext,
) => {
if (ctx.req.url?.startsWith('/_next')) {
return {
props: {},
};
}
return next?.(ctx)!;
};
And I add this to all my pages:
function getProps(ctx) {
// my logic
}
export const getServerSideProps = hasNavigationCSR(getProps);
Been using high order functions to features that I need to attach to a page, such as authorization, translation, initializing apollo client, etc.
It's a workaround, but works well and looks elegant with the other features: hasTranslations(hasApollo(hasAuth(hasNavigationCSR(getProps))))
If anyone doesn't want to wait for an official implementation, like me, that's what I'd recommend.
A similar approach to the above "solution" by adding isCSR
to the context with a factory function:
import { curry } from 'lodash/fp';
const gSSPWithCSRFlag = curry((gSSP, context) => {
if (gSSP && context) {
// Set a flag to context that checks if the request
// is coming from client side routing/navigation
context.isCSR = Boolean(context.req.url.startsWith('/_next'));
return Promise.resolve(gSSP(context));
}
throw Error('Either context or gSSP is not provided');
});
export default gSSPWithCSRFlag;
export const getServerSideProps = gSSPWithCSRFlag(async ({ isCSR, ...restCtx }) => { ...
I'm still facing this problem, currently my project using GraphQL
and next-urql
.
I have seen them solve this problem using by using react-ssr-prepass
https://github.com/FormidableLabs/urql/blob/main/packages/next-urql/src/with-urql-client.ts#L144
May be the best solution for now: still using getInitialProps
instead of getServerSideProps
and react-ssr-prepass
@nghiepit i'm facing this problem and using GraphQL
as well and i can confirm that next-urql
was the only "easy out of the box non hacky" way to resolve the issue specially that all the examples was about rest and i couldn't implement a similar with Apollo
Since we know when a route change starts and completes I don't see how this is a problem. For example, using a hook:
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
const useRouteChange = () => {
const router = useRouter();
const [routeChanging, setRouteChanging] = useState(false);
const handleRouteChangeComplete = () => setRouteChanging(false);
const handleRouteChangeStart = () => setRouteChanging(true);
useEffect(() => {
router.events.on('routeChangeComplete', handleRouteChangeComplete);
router.events.on('routeChangeStart', handleRouteChangeStart);
return () => {
router.events.off('routeChangeComplete', handleRouteChangeComplete);
router.events.off('routeChangeStart', handleRouteChangeStart);
};
}, [router]);
return { routeChanging };
};
export { useRouteChange };
Then a Spinner component:
const Spinner = () => {
const { routeChanging } = useRouteChange();
const [shouldShowSpinner, setShouldShowSpinner] = useState(false);
const timer = useRef<NodeJS.Timer>();
useEffect(() => {
if (routeChanging) {
// Only show spinner on page loads taking longer than 100ms.
timer.current = setTimeout(() => setShouldShowSpinner(true), 100);
} else {
setShouldShowSpinner(false);
if (timer.current) {
clearTimeout(timer.current);
}
}
}, [routeChanging]);
if (!shouldShowSpinner) {
return null;
}
return spinner component here;
Then in say _app.tsx
(could be used anywhere you want):
const App = ({ Component, pageProps }: AppProps) => (
...
<Component {...pageProps} />
<Spinner />
...
);
I use a timeout to only show the spinner on pages taking longer than 100ms, but if you want to show the spinner on every navigation the logic gets even simpler!
With this we get SSR without page reloads, and the user gets feedback when pages are loading.
For me what's missing is preloading of getServerSideProps data, just like with getStaticProps.
As it is now getServerSideProps is only called after clicking on a <Link>
, which is why it feels slow.
Should be super simple to implement (unless there's something I'm missing), not sure why it's not working that way already.
@timneutkens, do you know if this is in the pipeline? I haven't look at the code for next/link yet, if this is something that could be merged I might open a pull request!
Edit: I'm sorry! It seems you've already answered this question here: https://github.com/vercel/next.js/discussions/11578#discussioncomment-2997
any updates on this issue?
Hi All, any updates on this issue? do we have any alternative to achieve this functionality?
Hey guys. Any update about this? I have a similar use case with firebase/firestore. I Want to query it with firebase-admin server side, but with regular firebase client on the client side. This feature seems missing and is necessary to do proper SSR IMHO.
Im coming from CRA just months ago, and I must say I didn't realize how fast CRA is until I converted the App to NextJS (From a complex Web App point of view).
It's a major issue but let Vercel take their time to fix it...
Until then, I'm using Razzle by the creator of Formik.
Hi, any update on this?
Having the client block page transitions like this leads to a really poor user experience IMO.
I looked into the beta next-page-transitions
but that doesn't help solve this particular problem.
i don't believe why this important issue should last this long :(
i think this new patch can solve this problem https://github.com/vercel/next.js/releases/tag/v11.1.2
i think this new patch can solve this problem https://github.com/vercel/next.js/releases/tag/v11.1.2
How Exactly ?? can you describe ?
i think this new patch can solve this problem https://github.com/vercel/next.js/releases/tag/v11.1.2
How Exactly ?? can you describe ?
I'm sorry, my mistake :)))
@Kyoij
Do you have any idea how to use getServerSideProps should support props value as Promise
https://github.com/vercel/next.js/pull/28607 to make a loading state?
Also looking for the solution to use getServerSideProps
only on server. Is it really that hard to add an option to disable the fetch on the client? Can somebody help to find where to look in the Next.js repo to code something like that? I would try to create and use a cloned repo with such solution.
I wrote a proposal/RFC for an server-side only version of getServerSideProps
, getInitialServerSideProps
(ran only on the initial request, subsequent client-side navigation will have to do data fetching manually, for instance, with Apollo). I'm interested to hear if this would be a solution for the issues described here.
I'm working on a working prototype too, will share when ready.
One of the main issue is still not resolved. This delay b/w clicking and actual navigation is one of the biggest flaw in UX dictionary. Any impatient user may click several time as there is zero response on frontend side (even the link takes time to change)
Tried to bypass getSeverSideaProps by checking the request link but still that small delay exist because, a page having serverSideProps function must call that function before the actual navigation (that's annoying)
They should provide some workaround in Link component (like shallow prop does - but shallow prop work for the links within the same page), so a developer would be able to bypass that function call from navigation cycle (click -> getServerSideProps() -> page load)
Feature request
Is your feature request related to a problem? Please describe.
When clicking in a link to a page that uses
getServerSideProps
, the navigation will be kept in hold until the server response is complete, then the navigation will start. I want to be able to defer thegetServerSideProps
data-fetching until the client-side navigation has been completed. Similar to the behavior ofgetStaticProps
withfallback: true
.Describe the solution you'd like
gSSP
request should be fired to fetch the content and send it through the page props.I should be able to opt-in this behavior with a flag in the return of
gSSP
. The router should have a flag to tell if the page is fetching data:Describe alternatives you've considered
Using
getInitialProps
/getServerSideProps
to detect if it is client-side navigation and send empty props, then repeat the fetch logic in the component code