Summary : The structure is waiting for query to fully load before loading the page, it works almost like a PHP app where server render has to complete before the page is shown.
I'm trying to get it to at least load the website first , then query and load the server data. Let me provide more information below.
Hosted on Vercel. NextJS 13 App is currently on Beta.
I feel that i structured it wrongly causing the app to run like a server side rendering site. Could you please advise on structures for NextJS 13 App folder.
Route Structure
Route (app) Size First Load JS
┌ ○ / 0 B 0 B
├ λ /questions/[questionId] 144 B 66.8 kB
└ ○ /search
λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
○ (Static) automatically rendered as static HTML (uses no initial props)
From my understanding, NextJS 13 App , by default all are treated as ServerSide pages instead of Client unless you declare the client.
When the Link is clicked routed towards /questions , it will take 2.35 seconds before the UI will update , the 2.35 seconds was a fetch query "fetchQuestions" under the Question File (Code below)
Root File Summary
import Link from 'next/link';
import { Suspense } from 'react';
import { qLists } from '../typings';
import { SideBarRight } from './SideBarRight';
import { SideBarLeft } from './SideBarLeft';
const fetchqList = async () => {
const res = await fetch('https://example.com', {
next: { revalidate: 5 },
});
const data = await res.json();
const qLists: qLists[] = data;
return qLists;
};
async function Home() {
const qLists = await fetchqList();
{qLists.map((qList) => (
<Link href={`/questions/${qList.id}`}>
XXX
</Link>
))}
<SideBars />
return (xxx);
}
export default Home;
Question File Summary
import Link from 'next/link';
import { Suspense } from 'react';
import { SideBarLeft } from '../../SideBarLeft';
import SideBarRight from '../../SideBarRight';
type PageProps = {
params: {
questionId: string;
};
};
const fetchQuestions = async (questionId: string) => {
const res = await fetch(`https://exmaple.com/${questionId}`);
const questions = await res.json();
return questions;
};
async function questionPage({ params: { questionId } }: PageProps) {
const question = await fetchQuestions(questionId);
return (
<SideBarLeft />
<Suspense fallback={<p>Loading feed...</p>}>
{question.items[0].value}
</Suspense>
);
}
export default questionPage;
Related
When page is refreshed query is lost, disappears from react-query-devtools.
Before Next.js, I was using a react and react-router where I would pull a parameter from the router like this:
const { id } = useParams();
It worked then. With the help of the, Next.js Routing documentation
I have replaced useParams with:
import { usePZDetailData } from "../../hooks/usePZData";
import { useRouter } from "next/router";
const PZDetail = () => {
const router = useRouter();
const { id } = router.query;
const { } = usePZDetailData(id);
return <></>;
};
export default PZDetail;
Does not work on refresh. I found a similar topic, but manually using 'refetch' from react-query in useEffects doesn't seem like a good solution. How to do it then?
Edit
Referring to the comment, I am enclosing the rest of the code, the react-query hook. Together with the one already placed above, it forms a whole.
const fetchPZDetailData = (id) => {
return axiosInstance.get(`documents/pzs/${id}`);
};
export const usePZDetailData = (id) => {
return useQuery(["pzs", id], () => fetchPZDetailData(id), {});
};
Edit 2
I attach PZList page code with <Link> implementation
import Link from "next/link";
import React from "react";
import TableModel from "../../components/TableModel";
import { usePZSData } from "../../hooks/usePZData";
import { createColumnHelper } from "#tanstack/react-table";
type PZProps = {
id: number;
title: string;
entry_into_storage_date: string;
};
const index = () => {
const { data: PZS, isLoading } = usePZSData();
const columnHelper = createColumnHelper<PZProps>();
const columns = [
columnHelper.accessor("title", {
cell: (info) => (
<span>
<Link
href={`/pzs/${info.row.original.id}`}
>{`Dokument ${info.row.original.id}`}</Link>
</span>
),
header: "Tytuł",
}),
columnHelper.accessor("entry_into_storage_date", {
header: "Data wprowadzenia na stan ",
}),
];
return (
<div>
{isLoading ? (
"loading "
) : (
<TableModel data={PZS?.data} columns={columns} />
)}
</div>
);
};
export default index;
What you're experiencing is due to the Next.js' Automatic Static Optimization.
If getServerSideProps or getInitialProps is present in a page, Next.js
will switch to render the page on-demand, per-request (meaning
Server-Side Rendering).
If the above is not the case, Next.js will statically optimize your
page automatically by prerendering the page to static HTML.
During prerendering, the router's query object will be empty since we
do not have query information to provide during this phase. After
hydration, Next.js will trigger an update to your application to
provide the route parameters in the query object.
Since your page doesn't have getServerSideProps or getInitialProps, Next.js statically optimizes it automatically by prerendering it to static HTML. During this process the query string is an empty object, meaning in the first render router.query.id will be undefined. The query string value is only updated after hydration, triggering another render.
In your case, you can work around this by disabling the query if id is undefined. You can do so by passing the enabled option to the useQuery call.
export const usePZDetailData = (id) => {
return useQuery(["pzs", id], () => fetchPZDetailData(id), {
enabled: id
});
};
This will prevent making the request to the API if id is not defined during first render, and will make the request once its value is known after hydration.
I have a folder structure like this in my next app
├───blogs
│ ├───[slug].js
│ └───index.js
...
I published 2 blogs in Strapi. Lets say firstBlog and secondBlog.
In local everything works fine. But in a deployed app from vercel when I go to details of firstBlog everything works fine. But for the secondBlog it says 404 not found. I looked for answers but couldn’t find the problem. My slug.js:
import Layout from '../../components/Layout/layout'
import BlogPost from '../../components/Blog/blog'
import api from '../../api'
const Blog = ({ blog }) => {
return (
<Layout>
<BlogPost blog={blog} />
</Layout>
)
}
export const getStaticPaths = async () => {
const response = await api.getAllBlogs()
const paths = response.map(path => {
return {
params: {slug: path.attributes.slug.toString()}
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const slug = context.params.slug
const response = await api.getSingleBlog(slug)
return {
props: { blog: response }
}
}
export default Blog
and my api call is such as:
getSingleBlog(slug) {
return this.execute("get", `blogs?filters[slug]=${slug}&populate=categories`);
},
I think this is about my deployment in vercel. But couldn’t find the solution. Any ideas ?
When I test getServerSideProps() in development mode, prop data in my landing page is updated constantly, because the app is under fast build mode.
But when the app is deployed in vercel, the data in landing page is not updated even though my database (mongoDB) has been updated.
If I check Heroku logs (where backend is deployed), there is no POST request by client when I (user) visit landing page second time. Therefore, I am assuming that my browser uses the cached html page and not sending request to server.
Could anyone help me to explain what is the issue?
import { ApolloClient, InMemoryCache } from "#apollo/client";
import { GetServerSideProps } from "next";
import { GetAllPosts as query } from "#network/queries";
const client = new ApolloClient({
uri: //my backend uri,
cache: new InMemoryCache(),
});
//pages/_app.ts
import type { AppProps } from "next/app";
function MyApp({ Component, pageProps }: AppProps) {
return (
<ApolloProvider client={client}>
<AuthContext.Provider value={authService}>
<Component {...pageProps} />
</AuthContext.Provider>
</ApolloProvider>
);
}
//pages/index.tsx
export const getServerSideProps: GetServerSideProps = async () => {
let posts = [];
try {
const {
data: { getAllPosts },
} = await client.query({ query });
posts = !!getAllPosts.length && getAllPosts;
} catch (err) {
console.error(`----------error --------- ${err}`);
} finally {
return {
props: {
posts,
},
};
}
};
export default function Landing({ posts }: Props) {
////// react code
}
I'm building a simple Next.js website that consumes the spacex graphql API, using apollo as a client. I'm trying to make an api call, save the returned data to state and then set that state as context.
Before I save the data to state however, I wanted to check that my context provider was actually providing context to the app, so I simply passed the string 'test' as context.
However, up[on trying to extract this context in antoher component, I got the following error:
Error: The default export is not a React Component in page: "/"
My project is set up as follows, and I'm thinking I may have put the context file in the wrong place:
pages
-api
-items
-_app.js
-index.js
public
styles
next.config.js
spacexContext.js
Here's the rest of my app:
spaceContext.js
import { useState,useEffect,createContext } from 'react'
import { ApolloClient, InMemoryCache, gql } from "#apollo/client"
export const LaunchContext = createContext()
export const getStaticProps = async () => {
const client = new ApolloClient({
uri: 'https://api.spacex.land/graphql/',
cache: new InMemoryCache()
})
const { data } = await client.query({
query: gql`
query GetLaunches {
launchesPast(limit: 10) {
id
mission_name
launch_date_local
launch_site {
site_name_long
}
links {
article_link
video_link
mission_patch
}
rocket {
rocket_name
}
}
}
`
});
return {
props: {
launches: data.launchesPast
}
}
}
const LaunchContextProvider = (props) => {
return(
<LaunchContext.Provider value = 'test'>
{props.children}
</LaunchContext.Provider>
)
}
export default LaunchContextProvider
_app.js
import LaunchContextProvider from '../spacexContext'
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
return (
<LaunchContextProvider>
<Component {...pageProps} />
</LaunchContextProvider>
)
}
export default MyApp
Any suggestions on why this error is appearing and how to fix it?
i have created a nextjs app, i'm getting data from an express server deployed on netlify. i have created two pages, the first to display a list of users (i've got the users with getServerSideProps() function) and the second page is when you click on a user, you'll be redirected to the user profile (i've got the user's data with getStaticProps() and getStaticPaths() functions).
On localhost everything works fine.
But when i've tried to deploy the app on Netlify, i got this error while building it:
> Build error occurred 11:24:20 PM: Error: Export encountered errors on following paths /users/[userid]
The users list file:
import styles from "../../styles/Home.module.css";
import Link from "next/link";
export default function Users({ users }) {
return (
<div className={styles.container}>
{users.map((user) => (
<Link href={`/users/${user._id}`} key={user._id}>
{user.firstname}
</Link>
))}
</div>
);
}
export async function getServerSideProps() {
const res = await fetch("https://***************/api/users");
const users = await res.json();
return { props: { users} };
}
The profile file:
import React from "react";
export default function singleUser({ user }) {
return (
<div>
<h1>Hello {user.firstname}!</h1>
</div>
);
}
export async function getStaticPaths() {
const res = await fetch("https://***************************/api/users");
const users = await res.json();
const paths = users.map((user) => ({
params: { userid: user._id },
}));
return { paths, fallback: true };
}
// This also gets called at build time
export async function getStaticProps({ params }) {
const res = await fetch(`https://**********************/api/users/${params.userid}`);
const user = await res.json();
return { props: { user: user || {} }, revalidate: 3600 };
}