I'm trying to get a content by the slug param in the url inside a next js app. When using getServerSideProps, I can pass a context.query.id, but here I'm trying to use getStaticProps. This is what I have so far:
export async function getStaticProps() {
const apolloClient = initializeApollo();
const { data } = await apolloClient.query({
query: SLUG_QUERY,
});
return addApolloState(apolloClient, {
props: {
data,
},
revalidate: 60,
});
}
const SLUG_QUERY = gql`
query ($id: String!) {
postCollection(slug: { eq: $id }) {
items {
title
shortDescription
heroImg {
url
}
createdAt
slug
}
}
}
`;
I'm struggling to understand How can I pass the conbtext.query.id as a parameter in the gql query.
Thanks for the help
pass context into your getStaticProps function
export const getStaticProps = async (context) => {
then move your query inside the getStaticProps to use it
postCollection(slug: { eq: $context.params.id }) {
Alternatively, if you prefer to keep your query outside of the function (if you are reusing it elsewhere for example), then just wrap it in a function that takes the id as a parameter
const getPostCollectionQuery = (id) => {
const SLUG_QUERY = gql`
query ($id: String!) {
postCollection(slug: { eq: $id }) {
items {
title
shortDescription
heroImg {
url
}
createdAt
slug
}
}
}
`;
return SLUG_QUERY;
};
and then you can call that from your getStaticProps function
const { data } = await apolloClient.query({
query: getPostCollectionQuery(context.params.id),
});
Related
[I am upgrading my current NextJS site to the latest version of NextJS 13 with the app directory and using generateStaticParams, I keep getting the following error when migrating my getStaticPaths to the new app directory page, I am using GraphQL:
Error: A required parameter (slug) was not provided as a string in generateStaticParams for /[slug]
I've consoled the returns and it seems to be returning the correct object with strings, not sure what I am missing.
// app/[slug]/page.tsx
export async function generateStaticParams() {
const { data } = await client.query({
query: gql`
query getSlugs {
posts(first: 100) {
nodes {
slug
}
}
}
`,
})
const response = data.posts.nodes.map((post: Post) => post.slug)
const slugs = await response.map((slug: string) => ({ params: { slug } }))
return [{ slugs }]
/* returns
[{ params: { slug: 'blog-post-1' } }, { params: { slug: 'blog-post-2' } }...]
*/
}
async function getPost(params) {
const { data } = await client.query({
query: gql`
query singlePost {
post(id: "${params.slug}", idType: SLUG) {
content
categories {
nodes {
name
}
}
featuredImage {
node {
sourceUrl
}
}
postId
}
}
`,
})
return {data.post}
}
export default async function PostPage({ params }) {
const post = await getPost(params)
return <Post post={post} />
}
You must remove the params key inside the object you return, you must only return the slug.
export async function generateStaticParams() {
const { data } = await client.query({
query: gql`
query getSlugs {
posts(first: 100) {
nodes {
slug
}
}
}
`,
})
const response = data.posts.nodes.map((post: Post) => post.slug)
const slugs = response.map((slug: string) => ({ slug }))
return slugs
/* returns
[{ slug: 'blog-post-1' }, { slug: 'blog-post-2' }...]
*/
}
I'm building a Next.js app using GraphQL with ApolloClient to handle the API requests. I had a page working correctly and retrieving the correct data when passing an ID to the Next.js methods getStaticPaths and getStaticProps using inline gql queries as shown below.
const { data } = await client.query({
query: gql`
query Page {
page(id: "${slug}", idType: SLUG) {
title
}
}
`,
})
I have now started moving my gql queries to a separate queries.ts file and my issue is that I'm struggling to find a way to pass through the slug variable used in the request above. I tried the following but it did not work:
import { getPageQuery } from 'queries'
const { data } = await client.query({
query: getPageQuery,
})
// queries.ts
const getPageQuery = (slug: string) => gql`
query Page {
page(id: "${slug}", idType: SLUG) {
title
}
}
`
Looking for some information with regards to how I can keep my gql queries in a separate file and be able to pass in any dynamic data as required.
You need to create the slug variable.
eg:
export const getPageQuery = gql`
query ($slug: String!) {
page(where: { id: $slug }) {
title
}
}
`;
Here is how you can call that request:
const { data: res } = await client.query({
query: getPageQuery,
variables: { slug: slug },
});
I'm trying to pass a unique id to a GraphQL query to get all data against the id. But when I print the console it shows undefined. Note that if I want to see all posts the then it becomes successful by another query.
in my query.js file I have written the below query:
export const Unique_Post_Query= gql`
query SampleQueries($id: ID!) {
post(_id: $id) {
id
data {
title
body {
text
}
}
}
}`;
and the below code from another file where I'm trying to see the result of the query:
const id='e42fd2b5-b84a-4417-afd2-36cdbaa204dd';
const { data , error,loading} = useQuery(Unique_Post_Query, { variables: {id ,}, });
//const { error, loading, data } = useQuery(PROFILE_QUERY);
console.log('yourrrrr f data',data);
Please check below reference
const id='e42fd2b5-b84a-4417-afd2-36cdbaa204dd';
const { loading, data } = useQuery(Unique_Post_Query, {
variables: { id: id},
});
useEffect(() => {
if (data && data?.post) {
console.log("data: ", data?.post);
}
}, [data]);
I am trying to subscribe to a graphql-yoga subscription using apollo-client useSubscription hook
import React from 'react';
import {useSubscription,gql} from '#apollo/client';
const SUB_NEW_MSG = gql`
subscription SUB_NEW_MSG($chatRoom:ID!)
{
newMessage(chatRoom:$chatRoom)
}`;
function NewMsg(){
const { loading,error,data } = useSubscription(SUB_NEW_MSG,{
variables:{
chatRoom: "608851227be4796a8463607a",
},
});
if(loading) return <p>loading...</p>;
if(error) return <p>{error}</p>;
console.log(data);
return <h4>New Message:{data.newMessage}</h4>;
}
Network Status
But gives an error-
Error: Objects are not valid as a React child (found: Error: Variable "$chatRoom" of required type "ID!" was not provided.). If you meant to render a collection of children, use an array instead.
The schema at the backend is
type Subscription{
newMessage(chatRoom: ID!): String!
}
resolver is
const { pubsub } = require("../helper");
const { withFilter } = require("graphql-yoga");
module.exports = {
Subscription: {
newMessage: {
subscribe: withFilter(
() => pubsub.asyncIterator("newMessage"),
(payload, variables) => {
console.log(payload.query, variables, "HALO");
return payload.chatRoom === variables.chatRoom;
}
),
},
},
};
But when I pass the query like below,with no variables to useSubscription hook.Then it works
const SUB_NEW_MSG = gql`
subscription SUB_NEW_MSG
{
newMessage(chatRoom:"608851227be4796a8463607a")
}`;
What should I do?Are there any workarounds?
Change your query to this, and test it.
const SUB_NEW_MSG = gql`
subscription SUB_NEW_MSG($chatRoom: String!) {
newMessage(chatRoom: $chatRoom)
}
`;
I'm using next.js and the import { useRouter } from 'next/router'.
However on initial load, router.query.id is undefined. It quickly fills in, but that initial load is a killer.
I'm trying to figure out how to do it, and tried:
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
// const res = await fetch(`https://.../posts/${params.id}`)
// const post = await res.json()
console.log(params)
// Pass post data to the page via props
return { props: { params } }
}
but this returns an error:
Error: getStaticPaths is required for dynamic SSG pages and is missing for '/app/d/[id]'.
I can't use getStaticPaths, since [id] is variable and can be any number of things.
So what's the best way to handle this?
I would do smt like this(without staticProps):
function Page(props) {
const router = useRouter();
const { query = {} } = router || {};
const { id = 0 } = query || {};
useEffect(()=> {
if(id) {
(async ()=> {
const res = await fetch(`https://.../posts/${id}`)
const post = await res.json();
})();
}
}, [id]);
}
And this is what official doc. says:
// You also have to define a Post component in the same file (pages/posts/[id].js)
function Post({ post }) {
const router = useRouter()
// If the page is not yet generated, this will be displayed
// initially until getStaticProps() finishes running
if (router.isFallback) {
return <div>Loading...</div>
}
return <h1>Posts are here</h1>;
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return { props: { post } }
}
UPDATE:
After a bit research, have figure out this solution with staticProps:
export default function Post({ post }) {
return <h1>Post is here</h1>;
}
export async function getStaticPaths() {
return {
paths: [
{ params: { id: '*' } }
],
fallback: true
};
}
export async function getStaticProps(context) {
const res = await fetch(`https://api.icndb.com/jokes/random/${context.params.id}`);
const post = await res.json()
return { props: { post } }
}