SSR useQuery Breaking Page Transition

Technically using an infinite query, but I have an array of Posts that I'm prefetching, but when I use a next.js Link I get an undefined error during the transition
1 Reply
ryanagillie
ryanagillie3y ago
// Home (/)
// Only loads the first 10 posts for the query limit
const Home = () => {
const { data } = trpc.posts.posts.useQuery({});
const { posts } = data!; // prefetched, so should have a result

return (
<nav>
<Link href="/posts">Posts</Link>
{posts.map((post) => <Link key={post.id} href={`/posts/${post.id}`}>{post.title}</Link>)}
</nav>
);
};

export const getServerSideProps = async (ctx) => {
const ssr = ssrHelper(ctx);

await ssr.posts.posts.prefetch({});

return {
props: {
trpcState: ssr.dehydrate();
}
}
}
// Home (/)
// Only loads the first 10 posts for the query limit
const Home = () => {
const { data } = trpc.posts.posts.useQuery({});
const { posts } = data!; // prefetched, so should have a result

return (
<nav>
<Link href="/posts">Posts</Link>
{posts.map((post) => <Link key={post.id} href={`/posts/${post.id}`}>{post.title}</Link>)}
</nav>
);
};

export const getServerSideProps = async (ctx) => {
const ssr = ssrHelper(ctx);

await ssr.posts.posts.prefetch({});

return {
props: {
trpcState: ssr.dehydrate();
}
}
}
When I click on the non-looped link I get
Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'map')

<nav>
<Link href="/posts">Posts</Link>
{posts.map((post) => <Link key={post.id} href={`/posts/${post.id}`}>{post.title}</Link>)}
^
Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'map')

<nav>
<Link href="/posts">Posts</Link>
{posts.map((post) => <Link key={post.id} href={`/posts/${post.id}`}>{post.title}</Link>)}
^
Here's the code for /posts and /posts/[postId] (I use the home page to grab the top 10 posts, while the /posts uses a cursor based pagination
// /posts
const Posts: NextPage = () => {
const router = useRouter();

const { data } = trpc.posts.posts.useInfiniteQuery({}, { getNextPageParam: (lastPage) => lastPage.nextCursor });

return (
<>
<h1>Posts</h1>
<nav>
{data?.pages.map((page) => page.posts.map((post) => <Link key={post.id} href={`${router.asPath}/${post.id}`}>{post.title}</Link>))}
</nav>
</>
);
};
export default Posts;

export const getServerSideProps: GetServerSideProps = async (ctx) => {
const ssr = ssrHelper(ctx);

await ssr.posts.posts.prefetchInfinite({});

return {
props: {
trpcState: ssr.dehydrate(),
},
};
};
// /posts
const Posts: NextPage = () => {
const router = useRouter();

const { data } = trpc.posts.posts.useInfiniteQuery({}, { getNextPageParam: (lastPage) => lastPage.nextCursor });

return (
<>
<h1>Posts</h1>
<nav>
{data?.pages.map((page) => page.posts.map((post) => <Link key={post.id} href={`${router.asPath}/${post.id}`}>{post.title}</Link>))}
</nav>
</>
);
};
export default Posts;

export const getServerSideProps: GetServerSideProps = async (ctx) => {
const ssr = ssrHelper(ctx);

await ssr.posts.posts.prefetchInfinite({});

return {
props: {
trpcState: ssr.dehydrate(),
},
};
};
// /posts/[postId]
export type PostQuery = { postId: string };

const Post: NextPage = () => {
const router = useRouter();
const { postId } = router.query as PostQuery;

const { data: postData } = trpc.posts.post.useQuery(postId);
const post = postdData!;

const { data: commentsData } = trpc.posts.comments.comments.useInfiniteQuery({ postId }, { getNextPageParam: (lastPage) => lastPage.nextCursor });
const { pages } = commentsData!;

return (
<>
<h1>
Post
{' : '}
{post.title}
{' : '}
{post.id}
</h1>
{pages.map((page) => page.comments.map((comment) => (
<Link key={comment.id} href={`${router.asPath}/comments/${comment.id}`}>{comment.id}</Link>
)))}
</>
);
};
export default Post;

export const getServerSideProps: GetServerSideProps = async (ctx) => {
const { postId } = ctx.query as PostQuery;

const ssr = ssrHelper(ctx);

if (!await ssr.posts.post.fetch(postId)) {
return {
notFound: true,
};
}

await ssr.posts.comments.comments.prefetchInfinite({ postId });

return {
props: {
trpcState: ssr.dehydrate(),
},
};
};
// /posts/[postId]
export type PostQuery = { postId: string };

const Post: NextPage = () => {
const router = useRouter();
const { postId } = router.query as PostQuery;

const { data: postData } = trpc.posts.post.useQuery(postId);
const post = postdData!;

const { data: commentsData } = trpc.posts.comments.comments.useInfiniteQuery({ postId }, { getNextPageParam: (lastPage) => lastPage.nextCursor });
const { pages } = commentsData!;

return (
<>
<h1>
Post
{' : '}
{post.title}
{' : '}
{post.id}
</h1>
{pages.map((page) => page.comments.map((comment) => (
<Link key={comment.id} href={`${router.asPath}/comments/${comment.id}`}>{comment.id}</Link>
)))}
</>
);
};
export default Post;

export const getServerSideProps: GetServerSideProps = async (ctx) => {
const { postId } = ctx.query as PostQuery;

const ssr = ssrHelper(ctx);

if (!await ssr.posts.post.fetch(postId)) {
return {
notFound: true,
};
}

await ssr.posts.comments.comments.prefetchInfinite({ postId });

return {
props: {
trpcState: ssr.dehydrate(),
},
};
};
On the home page clicking on a post takes me to the posts/postId just fine, but that /posts link does something and kills my page transition? May be because of the caching / batching and how I'm treating an infinite query as a regular one on home but as a proper infinite on posts?
Want results from more Discord servers?
Add your server