Can't access multiple parameters of getStaticPaths from getStaticProps , Nextjs/Apollo/Graphql - javascript

Below you can check the code. I'm trying to use Id to identify single content and use titles for links,
when I console log params.title
console: android-paging-advanced-codelab
but
when I try to console log params.id,
console: undefined
I need to access both params inside the getStaticProps so I can use the exact data I need.
I did try context by passing context and using context.params.id but the result is the same.
read the code below and help me, please!
Here you can see the code of my getStaticPaths :
export async function getStaticPaths(){
const { data } = await client.query({
query: gql`
query {
postContents{
data{
attributes{
post_card{
data{
id
attributes{
TitleForLink
}
}
}
}
}
}
}
`
})
const paths = data.postContents.data.map((item)=> {
return {
params: {
id: item.attributes.post_card.data.id.toString(),
title: item.attributes.post_card.data.attributes.TitleForLink.toString(),
}
}
})
return {
paths,
fallback: false,
}
}
And the code of getStaticProps:
export async function getStaticProps({params}){
const { data } = await client.query({
query: gql`
query {
postCards{
data{
id
attributes{
post_content{
data{
id
attributes{
Title
Description
}
}
}
}
}
}
}
`
})
console.log(params.id)
return {
props: {
content: data.postCards.data,
}
}
}

The getStaticPaths function should return an object with paths parameters that determines which paths will be pre-rendered only, you can pass additional properties like locale if you have i18 configured.
So you need to make another fetching in the getStaticProps function.

Related

Passing context through createPage to use in a query, but a string is converted to a number so the query fails

I have a page creatin function wuth this:
createPage({
context: { productId: String(productId) },
As you see, I even forced the ID to be a string, but the page template still receives a number
const Template = ({ pageContext, data }) => {
console.log(pageContext.productId) // number
And the following query that expects a string fails:
export const query = graphql`
myStuff(filter: {productIdentifier: {eq: $productId}}) {
nodes {
id
}
}
}
`
Any ideas how I can force the productId to be a string?
Have you tried toString()?
createPage({
context: { productId: productId.toString() },
Even the productId is not being casted, you can also try defining it as a String or Int:
export const query = graphql`
query($productId: String!) {
myStuff(filter: {productIdentifier: {eq: $productId}}) {
nodes {
id
}
}
}
}
Use $productId: Int! otherwise but I don't know if this will match the filter though.
Another alternative is casting a new string variable before passing it to the context:
let productIdStringified = productId.toString()
createPage({
context: { productId: productIdStringified },

Why can't I get query params in ```getStaticProps```?

I will make it simple:
Link: http://localhost:3000/product/bioCloths?activeCategory=medium&id=0
File path: pages/product/[product].js.
Expected: product: "bioCloths, activeCategory: "medium", id: "0"
using getStaticProps at [product].js:
const ProductDetails = (props) => {
console.log("initial props", props);
return <div>product details...</div>
};
export default ProductDetails;
export async function getStaticProps(context) {
return {
props: {
context: context
},
};
}
export async function getStaticPaths() {
return {
paths: [{ params: { product: "1" } }, { params: { product: "2" } }],
fallback: true,
};
}
Props returns: context: params: product: "bioCloths", excluding the query params.
Now if I use the deprecated getInitialProps instead:
ProductDetails.getInitialProps = (context) => {
const activeCategory = context.query.activeCategory;
const id = context.query.id;
const product = context.query.product;
return {
activeCategory: activeCategory,
id: id,
product: product,
};
};
props logs activeCategory: "medium" id: "0" product: "bioCloths"
I need to get these all of these props so I can fetch data before the client mounts.
I understand that getInitialProps is now deprecated, but it works. Why is not getStaticProps working, and should I use it instead of serverSideProps?
This is an ecommerce, and there is no way I can set getStaticPaths for hundreds of possibilities, to work along with getStaticProps so I guess that in this case I should use getInitialProps or getServerSideProps?
P.S - getServerSideProps hits me an error stating that it will only accept .json files.
According to one of the maintainers of Nextjs this is the reply for anyone learning this framework:
getStaticProps generates the page at build time. There's no possible way to know the custom query params your visitors can use at build time.
getInitialProps and getServerSideProps can know all the possible query params because the page is generated at runtime, whenever you receive a new request.
You can learn more about the above here.
"
This discussion can be read on Github
If your page uses a dynamic route, params contain the route parameters. For instance, If the page name is [id].js, then params will look as follows:
{ id: /* something */ }
You can get URL params from inside your getStaticProps or getServerSideProps function with the context argument.
Here’s an example with getStaticProps:
// pages/[id].js
export async function getStaticProps(context) {
const { params } = context;
const id = params.id;
const data = /* Fetching data with the id */
return {
props: data,
}
}
You can do the same with getServerSideProps:
// pages/[id].js
export async function getServerSideProps(context) {
const { params } = context;
const id = params.id;
/* ... */
}

String interpolation is not allowed in graphql tag. (Gatsby)

Attempting to use an alias for a long complicated Ids within my graphql query:
FAILED TO COMPILE: String interpolation is not allowed in graphql tag:
const query = graphql`
query MyQuery {
wordpress {
menu(id: "${wordpress("mainMenu")}") {
...rest of query
}
}
}
`
You should use query variable instead.
Variables can be added to page queries (but not static queries) through the context object that is an argument of the createPage API. docs
// inside template file
export const query = graphql`
query MyQuery($id: String!) {
menu(id: { eq: $id }) {
...rest of query
}
}
`
Then you can provide such variable as part of the page’s context in gatsby-node.js. For example:
// gatsby-node.js
const postTemplate = path.resolve(`./src/templates/post.js`)
allWordpressPost.edges.forEach(edge => {
createPage({
path: `/${edge.node.slug}/`,
component: slash(postTemplate),
context: {
id: edge.node.id, // 👈
},
})
})
Have a look at this using-wordpress example from gatsby.

How to automatically include `.withGraphFetched()` for all queries of model in objection.js

I have the following model defined:
import db from "../connection.js";
import objection from "objection";
const { Model } = objection;
Model.knex(db);
class User extends Model {
static get tableName() {
return "users";
}
static get relationMappings() {
return {
emails: {
relation: Model.HasManyRelation,
modelClass: Email,
join: {
from: "users.id",
to: "emails.user_id",
}
}
}
}
}
class Email extends Model {
static get tableName() {
return "emails";
}
static get relationMappings() {
return {
user: {
relation: Model.BelongsToOneRelation,
modelClass: User,
join: {
from: "emails.user_id",
to: "users.id",
},
},
};
}
}
And to query a User with their email addresses would require withGraphFetched() to be explicitly run every time as:
const myUser = await User.query().withGraphFetched("emails").findById(1)
I haven't been able to figure out what to write in the Model definition to make this possible, and I don't see any such examples online. Is it possible to ALWAYS have withGraphFetched("emails") automatically included in the query so it doesn't have to be explicitly written out every time?
Such thing doesnt exist. Maybe you could create the logic in the beforeFind hook adding the eager loader to the knex instance, but it could generate a lot of undesired and strange side-effects.
The normal practice is adding a method to that specific case:
class User extends Model {
static get tableName() {
return "users";
}
static get relationMappings() {
return {
emails: {
relation: Model.HasManyRelation,
modelClass: Email,
join: {
from: "users.id",
to: "emails.user_id",
}
}
}
}
static async getUser (id) { // Or maybe getUserWithEmails
return await this.query().withGraphFetched("emails").findById(id)
}
}
Then you can just:
const myUser = await User.getUser(id)

Error: Network error: Error writing result to store for query:

Getting this error from Apollo:
core.js:14576 ERROR Error: Network error: Error writing result to store for query:
{"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdditionalServices"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"vendorID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},"directives":[]}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"vendor"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"vendorID"}}}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"services"},"name":{"kind":"Name","value":"products"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"productTypes"},"value":{"kind":"EnumValue","value":"service"}}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"isActive"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"cartSection"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"description"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"imageUrl"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"shortDescription"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}}]}}],"loc":{"start":0,"end":372}}
Store error: the application attempted to write an object with no provided id but the store already contains an id of Restaurant:200 for this object. The selectionSet that was trying to be written is:
{"kind":"Field","name":{"kind":"Name","value":"vendor"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"vendorID"}}}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"services"},"name":{"kind":"Name","value":"products"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"productTypes"},"value":{"kind":"EnumValue","value":"service"}}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"isActive"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"cartSection"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"description"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"imageUrl"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"shortDescription"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}}
at new ApolloError (ApolloError.js:25)
at QueryManager.js:276
at QueryManager.js:638
at Array.forEach (<anonymous>)
at QueryManager.js:637
at Map.forEach (<anonymous>)
at QueryManager.push../node_modules/apollo-client/core/QueryManager.js.QueryManager.broadcastQueries (QueryManager.js:632)
at QueryManager.js:226
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
at Object.onInvoke (core.js:16135)
This is the code that makes this happen:
this.restaurantID$.pipe(
takeUntil(this._ngOnDestroy)
)
.subscribe((restaurantID) => {
this.additionalServicesQuery$.next(this._apollo
.watchQuery<AdditionalServices>({
query: AdditionalServicesQuery,
variables: { vendorID: restaurantID }
}));
});
const loadAdditionalServicesData = this.additionalServicesQuery$
.pipe(
takeUntil(this._ngOnDestroy),
filter((query) => !!query),
switchMap((query) => query.valueChanges), // This is the switchMap that makes it happen
takeUntil(this._ngOnDestroy),
map((response) => response.data.vendor.services.nodes)
);
There is a SwitchMap that I commented if that is removed, the error does not happen. I can't understand what is going on.
query:
export const AdditionalServicesQuery = gql`
query AdditionalServices(
$vendorID: ID!
) {
vendor(
id: $vendorID
) {
services: products (productTypes: service) {
nodes {
id
isActive
cartSection {
id
name
}
description
imageUrl
shortDescription
name
}
}
}
}
`;
Update:
Added ID to query, still, same issue
export const AdditionalServicesQuery = gql`
query AdditionalServices(
$vendorID: ID!
) {
vendor(
id: $vendorID
) {
services: products (productTypes: service) {
id
nodes {
id
isActive
cartSection {
id
name
}
description
imageUrl
shortDescription
name
}
}
}
}
`;
According to that error, you need to add an id field (or _id field, whichever exists) to the selection set for the vendor field. Sounds like you already have another query that returns objects of the type Restaurant, that query included the id and was normalized properly. Apollo won't be able to combine the individual Restaurant objects from both queries unless an id is included.
export const AdditionalServicesQuery = gql`
query AdditionalServices(
$vendorID: ID!
) {
vendor(
id: $vendorID
) {
id # <----------------------------------------- ADD ME
services: products (productTypes: service) {
nodes {
id
isActive
cartSection {
id
name
}
description
imageUrl
shortDescription
name
}
}
}
}
`;

Categories