The data in Next.js shows as array, different from the JSON object returned by the API - reactjs

I fetch data from Laravel API using getServerSideProps():
This is how I fetch the data:
function Product({ data }) {
console.log(data);
return (
<div>Hello</div>
)
}
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`http://localhost:8000/api/products/`, {
method: 'GET',
})
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default Product
This is the output in the console:
So it means in order to get the actual value for a product I'll need to extract it from props like so: data.data[0].name - is there a better way to do it? It looks too complicated and prone to errors. Can I get a non-nested array in the first place?
*Also, the API returns a different object, and not an array like shown in the picture above
{"data":[{"id":1,"name":"some-product","price":"1250331.30","created_at":"2021-08-12T11:01:28.000000Z","updated_at":"2021-08-12T11:01:28.000000Z"},
{"id":2,"name":"some-other-product","price":"1141260.11","created_at":"2021-08-12T13:57:54.000000Z","updated_at":"2021-08-12T13:57:54.000000Z"}]}

You could use the destructuring notation ?
const { data } = await res.json()

Related

Axios API call returns a 404 on page render, but still returns api objects in terminal

I am using axios to make an api call to an api found on Apihub for a next JS app.
here is the code for the function to make the call to provide a list of property JSON objects.
export const baseUrl = "https://zillow56.p.rapidapi.com"
export const fetchApiListsingsCustom = async (url) => {
const { data } = await axios.get((url), {
method: 'GET',
headers: {
'X-RapidAPI-Key': '328713ab01msh862a3ad609011efp17e6b4jsn0e7112d5ee9a',
'X-RapidAPI-Host': 'zillow56.p.rapidapi.com'
}
});
data.then((res) => {
console.log(res);
})
.catch((error) => {
console.error(error);
});
return data.json();
}
When rendering the page I'm attempting to inject the response's data to dynamically create a list of apartment listings.
I'm trying to use getServerSideProps so that the data is already available by the time a user requests the page. After fetching the data, I want to also print them in the terminal to validate it's success.
export default function Home({ propertiesCustomdata })
export async function getServerSideProps() {
const propertiesCustom = await fetchApiListsingsCustom(`${baseUrl}`)
const propertiesCustomdata = propertiesCustom.json()
return {
props: {
propertiesCustomdata
}
}
}
The problem is, I seem to be getting a 404 error from the axios call, before the page gets a chance to load. When I access this I get a 404 error but I also manage to receive some contents of the call the API was to make.
My apologies if this is unclear, but this is all I know to report on this so far.
Studying async and await, fetch, and axios. Very confusing.

Sveltekit Actions returns garbled json

json returned from a Sveltekit actions is garbled. I would expect something like this:
{ foo: bar, foo2: bar2 }
But instead I get this:
Array({ foo: 1, foo2: 2 }, bar, bar2)
Which is even more annoying with nested data.
This is how I send it:
const response = await fetch('/api/fetch', {
method: 'POST'
}).then((res) => {
res.json().then((r) => {
console.log(JSON.parse(r.data))
})
})
This is api/fetch/+page.server.js
export const actions = {
default: async ({ request }) => {
const response = await fetch(
'https://exterual-url-that-returns-json', {
method: 'GET'
}
)
return await response.json()
}
}
I have the same problem even if the json object is not fetched from an external url, i.e. return { foo: bar, foo2: bar2 }
The JSON is not garbled but serialized via devalue which has fewer limitations than plain JSON.stringify, e.g. it retains Date, Set and Map objects.
The JSON is supposed to be consumed by SvelteKit code which should automatically convert it correctly. Actions are supposed to be used with <form> elements and the result is passed to the page in a form property; to process the request asynchronously, use the enhance action.
If you for some reason have to process the data manually, use the deserialize from $app/forms.

How to throw argument in RTK Query (queryFn)

I have queryFn query in RTK, and I need to get some data from firebase DB by element ID. But when I give this arg to queryFn like in example below, I got undefined.
and I'm calling it like this:
The reason you got undefined is because the useGetCardByIdQuery hook returns the data undefined initially. The data is going to be available after a success fetch.
As far I understand from your code, you are trying to get the cards of authorized firebase user; so you don't need to pass any id indeed since I see that you are not using the id in the queryFn.
In that case, just pass the undefined like useGetCardByIdQuery(undefined); and return the cardList.
And for better typing, you can define the builder query with <OutputType, InputType>
getCardsById: builder.query<CardList, string>({
queryFn: async (id, api, extraOptions, fetchWithBQ) => {
try {
const user = getAuth();
...
const cardList = cardSnapshot.docs.map(doc => doc.data())
return { data: cardList }
} catch (error) {
return { error }
}
},
})
Then you can call the hook in the component.
const response = useGetCardsByIdQuery(undefined);
if (response.data) {
const cards = response.data;
console.log(cards);
}

react-query: useQuery returns undefined and component does not rerender

I'm playing around with reactQuery in a little demo app you can see in this repo. The app calls this mock API.
I'm stuck on a an issue where I'm using the useQuery hook to call this function in a product API file:
export const getAllProducts = async (): Promise<Product[]> => {
const productEndPoint = 'http://localhost:5000/api/product';
const { data } = await axios.get(productEndPoint);
return data as Array<Product>;
};
In my ProductTable component I then call this function using:
const { data } = useQuery('products', getAllProducts);
I'm finding the call to the API does get made, and the data is returned. but the table in the grid is always empty.
If I debug I'm seeing the data object returned by useQuery is undefined.
The web request does successfully complete and I can see the data being returned in the network tab under requests in the browser.
I'm suspecting its the way the getAllProducts is structured perhaps or an async await issue but can't quite figure it out.
Can anyone suggest where IO may be going wrong please?
Simply use like this
At first data is undefined so mapping undefined data gives you a error so we have to use isLoading and if isLoading is true we wont render or map data till then and after isLoading becomes false then we can render or return data.
export const getAllProducts = async (): Promise<Product[]> => {
const productEndPoint = 'http://localhost:5000/api/product';
const res= await axios.get(productEndPoint);
return res.data as Array<Product>;
};
const { data:products , isLoading } = useQuery('products', getAllProducts);
if(isLoading){
return <FallBackView />
}
return (){
products.map(item => item)
}
I have managed to get this working. For the benefits of others ill share my learnings:
I made a few small changes starting with my api function. Changing the function to the following:
export const getAllProducts = async (): Promise<Product[]> => {
const response = await axios.get(`api/product`, {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
});
return response.data as Product[];
};
I do not de-construct the response of the axios call but rather take the data object from it and return is as an Product[]
Then second thing I then changed was in my ProductTable component. Here I told useQuery which type of response to expect by changing the call to :
const { data } = useQuery<Product[], Error>('products', getAllProducts);
Lastly, a rookie mistake on my part: because I was using a mock api in a docker container running on localhost and calling it using http://localhost:5000/api/product I was getting the all to well known network error:
localhost has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present...
So to get around that for the purpose of this exercise I just added a property to the packages.json file: "proxy":"http://localhost:5000",
This has now successfully allowed fetching of the data as I would expect it.

getStaticProps with SWR "Error serializing `.initialData.config.transformRequest[0]` returned from `getStaticProps`"

I'm trying to use SWR in Next.js env.
const Best = (props: InferGetStaticPropsType<typeof getStaticProps>) => {
const { data } = useSWR('/best', apis.getBestProduct, {
initialData: props.initialData,
});
console.log(data);
return (
...SOME PRESENTER
);
};
export const getStaticProps: GetStaticProps = async () => {
const data = await apis.getBestProduct();
return { props: { initialData: data } };
};
export default Best;
I want to use useSWR with getStaticProps.
But this code makes error like this.
Server Error
Error: Error serializing `.initialData.config.transformRequest[0]` returned from `getStaticProps` in "/best".
Reason: `function` cannot be serialized as JSON. Please only return JSON serializable data types.
The data came well, I don't know why it doesn't work.
I'm using MacOS, custom Node.js server, and this is localhost.
getStaticProps sends your data to the front end by first serializing it with JSONā€”that is, it transforms data from a runtime JavaScript object into a string that can be parsed into a runtime JavaScript object by your front end.
However, JSON has certain limitations, one of which is that it cannot serialize functions. And somewhere in your data object you have a value that is a function. You need to clean up this data object before you return it from getStaticProps.
For example, suppose data.myFunction is a function, you could do something like:
export const getStaticProps: GetStaticProps = async () => {
const {myFunction, ...data} = await apis.getBestProduct();
return { props: { initialData: data } };
};
This will remove myFunction and leave all the other keys in data.

Resources