Hope you are well.
I am working on a Next.js project, we have a searchbar in the homepage whose method is located inside the file /pages/search.page.tsx and it runs through the getServerSideProps method.
We came into this bug that affects the search results pagination in production, not any issue in local development or local build.
Basically once a search query is executed the app renders the first bunch of results at: https://www.example.com/search/?s=what-you-have-searched/
So far so good.
However when we try to go ahead with the page results, it keeps rendering the first page because the 'skip' param is not read/received even if it appears in the url like so:
https://www.example.com/search/?s=what-you-have-searched&**skip=15**&type=articolo%2Cgallery%2Cvideo/
export const getServerSideProps: GetServerSideProps = async ({ query }) => {
const apolloClient = initializeApollo();
const typeNews = [TypeContent.NEWS, TypeContent.PHOTO, TypeContent.VIDEO];
const fieldValue = query?.s || "";
const skip = +query?.skip || 0;
const type = query?.type || typeNews.join(",");
const params = getParams(fieldValue, type, skip);
const { data } = await apolloClient.query({
query: GET_CONTENTS,
variables: { ...params },
});
return {
props: {
postData: {
data
},
},
};
};
As mentioned above, we do not have any issue locally running the app through
yarn dev or yarn start
the bug shows up only when in production.
Basically the 'skip' url params destructured from the object query always return 0 even if the url contains a different value.
What might be wrong?
How can i debug it in production to see what values we receive from the query object?
Thanks
Related
i was trying to fetch a data for a project but everytime i'm converting the fetch data to json it returns me
SyntaxError: Unexpected token < in JSON at position 0
i don't understand why it's showing me this
import React,{useContext,useState,useEffect} from 'react'
const url = 'www.thecocktaildb.com/api/json/v1/1/search.php?s='
export default function AppProvider({children}) {
const [loading,setLoading] = useState(true)
const [searchTerm,setSearchTerm] = useState('a')
//set it as 'a' for suggestion at search bar at beginning.
const [cocktails,setCocktails] = useState([])
const fetchUrl = async ()=>{
setLoading(true)
try {
const response = await fetch(`${url}${searchTerm}`)
//(${url}${searchterm} helps me to fetch data at first with names that starts with 'a' for suggestion///
const data = await response.json()
setLoading(false)
} catch (error) {
console.log(error)
}
}
useEffect(()=>{
fetchUrl()
},[searchTerm])
please visit the API page from the URL & see if there's an issue with the data. the data is not fetching. what's the issue?
Link
Doing
fetch('www.thecocktaildb.com/')
will fetch not that website, but that path relative to the current path. For example, doing so here on Stack Overflow results in the URL being fetched being
https://stackoverflow.com/questions/72914244/www.thecocktaildb.com/
which, of course, doesn't exist - and presumably that URL doesn't exist on your site either.
Use the full path.
const url = 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s='
I'd also recommend only calling the API when searchTerm isn't empty, and perhaps add a debounce of a few hundred milliseconds so as not to call it too often and to keep the client from being blocked.
I'm using dynamic routes and using fallback:true option to be able to accept newly created pages
first i check if parameters is true then i create related props and show the component with that props.
In console i can also see that next.js create new json file for that related page to not go to server again for the next requests to the same page.
But even I type wrong address next create new json file for that path. It means that next.js create json file for every wrong path request.
How can avoid that vulnerable approach?
export const getStaticProps: GetStaticProps = async ({ params }) => {
if (params.slug[0] === "validurl") {
const { products } = await fetcher(xx);
const { categories } = await fetcher(xx);
return { props: { categories, products } };
} else {
return { props: {} };
}
};
const Home = (props: any) => {
if (!props) {
return <div>404</div>;
}
return (
<MainLayout {...props}>
<FlowItems items={props.products} />
</MainLayout>
);
};
export async function getServerSideProps(context) {
console.log(context.params.slug);
...
You are in Server Side inside this getServerSideProps and passing the context lets you dynamically catch whatever value it takes for whatever request.
Then you can check the data you want to load like:
const slug = context.params.slug;
const data = await fetch(`${host}/endpoint/${slug.join('/')}`);
so the request will be like 'localhost:3000/endpoint/foo/slug/test
Then you can deal with those slugs and it's data in a backend logic (where it should be) in your endpoint (just to clarify this sort of logic it usually belongs to a gateway and not to an endpoint, this is just for educational purposes).
If the endpoint/gateway returns a 404 - Not found you can simply redirect to the 404.js page (which can be static), same for the rest of the possible errors available in your backend.
I am making an eCommerce platform using Next.js. In the product page, where I use dynamic routes, I used getStaticProps to fetch my product and getStaticPaths to generate the paths to the products that should be statically generated. This works perfectly in development mode but the project does not build. The product prop which is passed from getStaticProps to the page component is undefined in build time.
This is the error I get when trying to build:
Error occurred prerendering page "/product/[id]". Read more:
https://err.sh/next.js/prerender-error TypeError: Cannot destructure
property 'name' of 'product' as it is undefined.
function ProductPage({ product}) {
// product is defined in development but undefined when trying to build
const {
name,
price,
} = product;
// The rest of the component
}
export const getStaticPaths = async () => {
connectDb();
const products = await Product.find();
const paths = products.map(product => ({
params: { id: product._id.toString() },
}));
return {
paths,
fallback: true,
};
};
export const getStaticProps = async ({ params }) => {
connectDb();
const { id } = params;
try {
// getting the product
const product = await Product.findOne({ _id: id });
return {
props: {
product: JSON.parse(JSON.stringify(product)),
},
};
} catch (err) {
console.log(err);
return {
props: {
product: {},
},
};
}
};
export default ProductPage;
why is the product prop defined in development mode but undefined in build time, and how can I fix this?
I recently encountered the exact same issue. I'm not sure what you have put in your //the rest of the component section but I noticed in the getStaticPaths function you specify fallback: true. Make sure you handle this in the page component by adding a skeleton or a loading indicator for pages that didn't yet exist at build time. That did the trick for me.
Looking over the code it seems like the product is undefined likely because the code in the try block failed to return data (or you didn't find a matching document in the MongoDB database?). Can you verify that no error occurs?
This can happen if you're passing the id param as "string" while in your MongoDB database the _id field is of type "ObjectID". You can remedy that by converting the "id" string to an ObjectID using the MongoDB package.
I'm in the process of setting a graphql endpoint with servlerless/ lambda and am receiving an error when trying to connect to the graphql playground that comes with graphql-yoga. When I go to my route that has the playground (/playground) it launches the playground interface however it just says:
Server cannot be reached
In the top right of the playground. It's worth noting i'm using the makeRemoteExecutableSchema utility to proxy to another graphql endpoint (which is my CMS called Prismic). I don't believe this is the issue as I have successfully connected to it with the playground when testing on a normal express server.
Here is the code in my handler.js
'use strict';
const { makeRemoteExecutableSchema } = require('graphql-tools');
const { PrismicLink } = require("apollo-link-prismic");
const { introspectSchema } = require('graphql-tools');
const { ACCESS_TOKEN, CMS_URL } = process.env;
const { GraphQLServerLambda } = require('graphql-yoga')
const lambda = async () => {
const link = PrismicLink({
uri: CMS_URL,
accessToken: ACCESS_TOKEN
});
const schema = await introspectSchema(link);
const executableSchema = makeRemoteExecutableSchema({
schema,
link,
});
return new GraphQLServerLambda({
schema: executableSchema,
context: req => ({ ...req })
});
}
exports.playground = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const graphQl = await lambda();
return graphQl.playgroundHandler(event, context, callback);
};
I have followed this guide for getting it running up till here and am fairly sure i've followed similar steps for what applies to what i'm trying to do but can't seem to figure out where i've gone wrong.
Thanks,
Could you take a look at what version of the graphql-yoga package you are using?
I had a similar problem using the Apollo server in combination with Kentico Cloud Headless CMS and I found this issue:
https://github.com/prisma/graphql-yoga/issues/267
I'm new to nuxt.js so I'm wondering what could be the best way to set up some data via REST api.
I have a store folder like this:
store
-posts.js
-categories.js
-index.js
I've tried to set the data with nuxtServerInit actions in the index.js:
export const actions = {
async nuxtServerInit({ dispatch }) {
await dispatch('categories/setCategories')
await dispatch('posts/loadPosts','all')
}
}
But doesn't works: actions are dispatched (on the server) but data are not set.
So I've tried with fetch but this method is called every time the page where I have to display posts is loaded. Even if, in the general layout, I do this:
<template>
<div>
<Header />
<keep-alive>
<nuxt/>
</keep-alive>
</div>
</template>
So my solution, for now, is to use fetch in this way,
In the page component:
async fetch({store}){
if(store.getters['posts/getPosts'].length === 0 && store.getters['categories/getCategories'].length === 0 ){
await store.dispatch('categories/setCategories')
await store.dispatch('posts/loadPosts','all')
}
}
Also, one thing I noted is that fetch seems not working on the root page component (pages/index.vue)
My solution seems works, but there is maybe another better way to set the data?
There's no out of the box solution for this as it's specific to your requirements/needs. My solution is very similar to yours but instead of checking the size of data array I introduced additional variable loaded in every store module. I only fetch data if loaded is false. This approach is more suitable in apps that have user generated content and require authentication. It will work optimally with SSR and client-side, and it won't try to fetch data on every page visit if user has no data.
You could also simplify your fetch method like this:
async fetch()
{
await this.$store.dispatch('posts/getOnce')
}
Now your posts.js store module will look something like this:
export const state = () => ({
list: [],
loaded: false
})
export const actions = {
async getOnce({ dispatch, state }) {
if (!state.loaded) {
dispatch('posts/get')
}
},
async get({ commit, state }) {
await this.$axios.get(`/posts`)
.then((res) => {
if (res.status === 200) {
commit('set', res.data.posts)
}
})
}
}
export const mutations = {
set(state, posts) {
state.list = posts
state.loaded = true
}
}