How to display 404 error page with react-query in next-ssr - next.js

I am using react query as stated in the doc
But, I am not sure how to return {notFound: true} from getServerSideProps. Could anyone help me how to handle this?
My code ins getServerSideProps is:
const queryClient = new QueryClient();
await queryClient.prefetchQuery('amenities', () => getAmenities(params?.id as string));
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
Now, what I want to do is, if the response is 404, then return 404 from getServerSideProps.
Update: I was not able to find any solution so removed react query in getServerSideProps. Now I'm fetching the data normally.

what you can do is do it on the client side.
const { data, isLoading, isError } = useQuery(
["amenities", router.query.id],
() => getAmenities(router.query.id)
)
if(isError) router.push('404');
You can do it in the server side too
const queryClient = new QueryClient();
const data = await queryClient.prefetchQuery('amenities', () => getAmenities(params?.id as string));
if (!data) {
return {
notFound: true,
}
}
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};

Related

Can i dispatch many actions in getServersideprops?

In my social media app in Home page i want to dispatch 3 actions from my api:
posts , users , userDetails
But this may show an error(500) on vercel because the request takes a lot of time to get all these data.
vercel Error
this error will not appear again after refreshing the page !!!
i think that's because the request takes a lot of time to get all the data.
-> getServersideProps Code
export const getServerSideProps = wrapper.getServerSideProps(
store => async (context) =>
{
const {req} = context
const session = await getSession({ req });
await store.dispatch(fetchPostsAction());
await store.dispatch(fetchUsersAction(4));
await store.dispatch(LoggedInUserAction({email:session.user.email}));
})
-> fetchPostsAction Code
"post/list",
async (_, { rejectWithValue, getState, dispatch }) => {
try
{
let link = `${URL}/api/posts`;
const { data } = await axios.get(link,{
headers: { "Accept-Encoding": "gzip,deflate,compress" }
});
console.log("#2 got the data",data)
return data;
} catch (error) {
if (!error?.response) throw error;
return rejectWithValue(error?.response?.data);
}
}
);
-> extraReducer Code
builder.addCase(createpostAction.pending, (state, action) => {
state.createPostLoading = true;
});
builder.addCase(createpostAction.fulfilled, (state, action) => {
state.postLists = [...state.postLists, action.payload.post].sort((a, b) => b.createdAt > a.createdAt ? 1 : -1)
state.createPostLoading = false;
state.isCreated = true;
state.appErr = null;
state.serverErr = null;
});
builder.addCase(createpostAction.rejected, (state, action) => {
state.createPostLoading = false;
state.appErr =
action?.payload?.message || action?.payload?.error?.message;
state.serverErr = action?.error?.message;
});
-> get posts from api Code
handler.get(async (req, res) =>
{
await db.connect();
try {
const posts = await Post.find().populate({
path: 'user',
model: 'User',
}).populate({
path:'comments',
options: {sort: {'createdAt' : -1} }
}).sort('-createdAt')
res.status(200).json({
success:true,
posts
});
} catch (err) {
res.status(500).json(err.message)
}
await db.disconnect();
})
so what is the best way to fetch all these data in next js ?
I hope there is a way to solve this problem

TypeError: Failed to fetch next js

When trying to get data in next js, the server does not return anything at all, the console is empty, tell me, please, what could be wrong?
export const getStaticProps = async () => {
const res = await fetch('https://api.jikan.moe/v4/top/manga');
const data = await res.json();
console.log('data >>>', data);
return {
props: {
manga: data,
},
};
};

How to fix undefined` cannot be serialized as JSON. Please use `null` or omit this value using getStaticprops

i am trying to fetch some data from an api using getStaticProps with next js. It returns the error undefinedcannot be serialized as JSON. Please usenull` or omit this value.
I have amended the code based on the solutions proposed online about the topic but none of them work.
export async function getStaticProps() {
const propertyForSale = await fetchApi(`${baseUrl}/properties/list?locationExternalIDs=5002&purpose=for-sale&hitsPerPage=6`);
const propertyForRent = await fetchApi(`${baseUrl}/properties/list?locationExternalIDs=5002&purpose=for-rent&hitsPerPage=6`);
return {
props: {
// Initial code
propertyForSale: propertyForSale?.hits,
propertyForRent: propertyForRent?.hits,
// the below snippet fixes the issue but return null
// propertyForSale: propertyForSale?.hits ?? null,
//propertyForRent: propertyForRent?.hits ?? null,
//the below snippet fixes the issue but return Unexpected token u in JSON at position 0
// propertyForSale: JSON.stringify(JSON.parse(propertyForSale?.hits))
//propertyForRent: JSON.stringify(JSON.parse(propertyForRent?.hits)),
}
}
}
fetchapi.js
export const baseUrl = 'https://bayut.p.rapidapi.com'
export const fetchApi = async (url) => {
const {result} = await axios.get((url), {
headers: {
'x-rapidapi-host': 'bayut.p.rapidapi.com',
'x-rapidapi-key': process.env.NEXT_PUBLIC_BAYU_API
},
});
console.log(result);
return result;
};
As Lazar pointed out in his comment, in your question's code snippet, you're trying to destructure a property that doesn't exist. And since axios returns an object with the data property, you're only left with destructuring the correct property:
const { data } = await axios.get(.....)
or...
const result = await axios.get(.....);
return result.data;
if you insist on the result thing :D
To fix the error I renamed constant result to data as per below.
I am not sure of what is the reason of this bug, if someone wanna add something to explain the reason why naming the constant data fixed the bug be my guess.
export const fetchApi = async (url) => {
const {data} = await axios.get((url), {
headers: {
'x-rapidapi-host': 'bayut.p.rapidapi.com',
'x-rapidapi-key': process.env.NEXT_PUBLIC_BAYU_API
},
});
return data;
};
export async function getStaticProps() {
const propertyForSale = await fetchApi(`${baseUrl}/properties/list?locationExternalIDs=5002&purpose=for-sale&hitsPerPage=6`);
const propertyForRent = await fetchApi(`${baseUrl}/properties/list?locationExternalIDs=5002&purpose=for-rent&hitsPerPage=6`);
return {
props: {
// Initial code
propertyForSale: propertyForSale?.hits,
propertyForRent: propertyForRent?.hits,
}
}
}
can you try this please?
return {
props: {
propertyForSale: propertyForSale?.hits || null,
propertyForRent: propertyForRent?.hits || null,
}
}

Handling errors with redux-toolkit

The information about the error in my case sits deeply in the response, and I'm trying to move my project to redux-toolkit. This is how it used to be:
catch(e) {
let warning
switch (e.response.data.error.message) {
...
}
}
The problem is that redux-toolkit doesn't put that data in the rejected action creator and I have no access to the error message, it puts his message instead of the initial one:
While the original response looks like this:
So how can I retrieve that data?
Per the docs, RTK's createAsyncThunk has default handling for errors - it dispatches a serialized version of the Error instance as action.error.
If you need to customize what goes into the rejected action, it's up to you to catch the initial error yourself, and use rejectWithValue() to decide what goes into the action:
const updateUser = createAsyncThunk(
'users/update',
async (userData, { rejectWithValue }) => {
const { id, ...fields } = userData
try {
const response = await userAPI.updateById(id, fields)
return response.data.user
} catch (err) {
if (!err.response) {
throw err
}
return rejectWithValue(err.response.data)
}
}
)
We use thunkAPI, the second argument in the payloadCreator; containing all of the parameters that are normally passed to a Redux thunk function, as well as additional options: For our example async(obj, {dispatch, getState, rejectWithValue, fulfillWithValue}) is our payloadCreator with the required arguments;
This is an example using fetch api
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
export const getExampleThunk = createAsyncThunk(
'auth/getExampleThunk',
async(obj, {dispatch, getState, rejectWithValue, fulfillWithValue}) => {
try{
const response = await fetch('https://reqrefs.in/api/users/yu');
if (!response.ok) {
return rejectWithValue(response.status)
}
const data = await response.json();
return fulfillWithValue(data)
}catch(error){
throw rejectWithValue(error.message)
}
}
)
Simple example in slice:
const exampleSlice = createSlice({
name: 'example',
initialState: {
httpErr: false,
},
reducers: {
//set your reducers
},
extraReducers: {
[getExampleThunk.pending]: (state, action) => {
//some action here
},
[getExampleThunk.fulfilled]: (state, action) => {
state.httpErr = action.payload;
},
[getExampleThunk.rejected]: (state, action) => {
state.httpErr = action.payload;
}
}
})
Handling Error
Take note:
rejectWithValue - utility (additional option from thunkAPI) that you can return/throw in your action creator to return a rejected response with a defined payload and meta. It will pass whatever value you give it and return it in the payload of the rejected action.
For those that use apisauce (wrapper that uses axios with standardized errors + request/response transforms)
Since apisauce always resolves Promises, you can check !response.ok and handle it with rejectWithValue. (Notice the ! since we want to check if the request is not ok)
export const login = createAsyncThunk(
"auth/login",
async (credentials, { rejectWithValue }) => {
const response = await authAPI.signin(credentials);
if (!response.ok) {
return rejectWithValue(response.data.message);
}
return response.data;
}
);

App working locally but not on production: TypeError: Cannot read property 'titulo_categoria' of undefined

I'm trying to deploy an app using Prismic as CMS and everything works perfectly locally, but once I deploy to vercel I get the error:
19:09:51.850 | TypeError: Cannot read property 'titulo_categoria' of undefined
There seems to be something wrong when it tries to get the data from Prismic.
My code is the following:
import {getAllCategorias, getCategory2} from '../../lib/api';
export default function Index({cat}) {
return <>{cat.titulo_categoria[0].text}</>;
}
export async function getStaticProps({params}) {
const data = await getCategory2(params.slug);
return {
props: {
cat: data?.categorias ?? null,
},
};
}
export async function getStaticPaths() {
const allPosts = await getAllCategorias();
return {
paths: allPosts?.map(({node}) => `/test/${node._meta.uid}`) || [],
fallback: true,
};
}
And the API code that gets data from Prismic is:
import Prismic from 'prismic-javascript';
const REPOSITORY = process.env.PRISMIC_REPOSITORY_NAME;
const REF_API_URL = `https://${REPOSITORY}.prismic.io/api/v2`;
const GRAPHQL_API_URL = `https://${REPOSITORY}.prismic.io/graphql`;
// export const API_URL = 'https://your-repo-name.cdn.prismic.io/api/v2'
export const API_TOKEN = process.env.PRISMIC_API_TOKEN;
export const API_LOCALE = process.env.PRISMIC_REPOSITORY_LOCALE;
export const PrismicClient = Prismic.client(REF_API_URL, {
accessToken: API_TOKEN,
});
async function fetchAPI(query, {previewData, variables} = {}) {
const prismicAPI = await PrismicClient.getApi();
const res = await fetch(
`${GRAPHQL_API_URL}?query=${query}&variables=${JSON.stringify(variables)}`,
{
headers: {
'Prismic-Ref': previewData?.ref || prismicAPI.masterRef.ref,
'Content-Type': 'application/json',
'Accept-Language': API_LOCALE,
Authorization: `Token ${API_TOKEN}`,
},
}
);
if (res.status !== 200) {
console.log(await res.text());
throw new Error('Failed to fetch API');
}
const json = await res.json();
if (json.errors) {
console.error(json.errors);
throw new Error('Failed to fetch API');
}
return json.data;
}
export async function getCategory2(slug) {
const data = await fetchAPI(
`
query CategoryBySlug($slug: String!, $lang: String!) {
categorias(uid: $slug, lang: $lang) {
titulo_categoria
_meta {
uid
}
}
}
`,
{
variables: {
slug,
lang: API_LOCALE,
},
}
);
return data;
}
Any idea what's wrong with this? I been trying to figure it out for the whole day without any luck
Perhaps you already checked that, but since you mentioned everything works locally and not on Vercel are you sure your environment variables are set there? Especially PRISMIC_API_TOKEN since it appears you're relying on it to query the API?
Also I'm a bit worried about that part of the code:
props: {
cat: data?.categorias ?? null,
}
...where you might be sending a null value to your Index component resulting in your error, I'd try that instead:
props: {
cat: data?.categorias ?? {},
}
...plus using the safe navigation operator (?.) on the Index component?
Let me know how it goes!

Resources