Fetch data request to nested JSON object error - React/Next.JS - javascript

I'm having problems fetching data from my API and I get this error. I have attached the JSON format below as I believe it is an issue with my structure. When I use a different res URL with objects nested inside an array, it works. But for my data, it is not. Can anyone help me please?
"Index.getInitialProps()" should resolve to an object. But found undefined instead"
import Layout from '../comps/Layout';
import Link from 'next/link';
import fetch from 'isomorphic-unfetch';
const Index = props => (
<Layout>
//List of movies here
</Layout>
);
Index.getInitialProps = async function() {
const res = await fetch('https://www.what-song.com/api/recent-movies')
const data = await res.json()
console.log(`Data: ${data}`)
}
export default Index;

The getInitialProps method basically supposed to set your component initial props. But, in your case you are returning nothing.
So, change your code to
Index.getInitialProps = async function() {
const res = await fetch('https://www.what-song.com/api/recent-movies')
const data = await res.json()
console.log(`Data: ${data}`)
return { data }; // <-- set whatever key you want.
}
For your reference

Related

Storing All the data coming from API call based on some parameters in a List

I Have a list containing some ids, I have to call an api with each of ids in the list and store all the data that comes from the api in a list,I am mapping through the list and calling the api with each id and then pushing the data into an array,but when I finally check the array it gives inconsistent result,sometimes it returns all the data,some time some of the data or sometimes the list is empty,here is my react code
let deviceidlist=['eb77fa554fbdbed47dkubk','ebbaa8d217947ff4d1fk3w','ebe55d36879c7fd71emtf0','eb645acaa1efb456877nss','ebc32ad422bc5dc3eecapa','ebf5bb435e688e96e8mt5z','45102754e09806133d2d','eb7c72ba426f92b9a1pb81','eb84a574ecfa372e6ccapr','eb458f73adadf67170uxdv']
let devicelist=[]
useEffect(()=>{
const datafetch=async()=>{
deviceidlist.map((item)=>{fetch(`http://localhost:8000/api/switch/${item}`).then(data=>data.json()).then(data=>devicelist.push(data))})
}
datafetch()
}
,[])
console.log(devicelist)
I am trying to store all the data that I get back from api to store in a list but getting an empty array
Fetching data from API is an asynchronous task, consoling right after the API call may not give the expected result. That's the reason you are getting multiple results
try adding the deviceList to a state so it will be
const[deviceList, setDeviceList] = useState([]);
useEffect(()=>{
const datafetch=async()=>{
deviceidlist.map((item)=>{fetch(`http://localhost:8000/api/switch/${item}`).then(data=>data.json()).then(data=>{
setDeviceList([...deviceList, data]);
})})
}
datafetch()
}
,[])
Try consoling the deviceList (state update will re-render the component and will console the updated data)
Try to fetch the data asynchronously and then set it to the state instead of pushing it into the array. Something like this :
import React from 'react';
import { useEffect } from 'react';
export default function App() {
let deviceidlist = [
'eb77fa554fbdbed47dkubk',
'ebbaa8d217947ff4d1fk3w',
'ebe55d36879c7fd71emtf0',
'eb645acaa1efb456877nss',
'ebc32ad422bc5dc3eecapa',
'ebf5bb435e688e96e8mt5z',
'45102754e09806133d2d',
'eb7c72ba426f92b9a1pb81',
'eb84a574ecfa372e6ccapr',
'eb458f73adadf67170uxdv',
];
const deviceList = [];
useEffect( async() => {
try {
let response = await deviceidlist.map((item) => { fetch(`http://localhost:8000/api/switch/${item}`) })
if (response.ok) {
let data = await response.json()
deviceList.push(data)
} else {
console.log("failed")
}
} catch(error) {
console.log(error)
}
})
return (
<div></div>
);
}

Axios is not getting response on first load

I am new in React JS and trying to get the data inside useEffect and I have a separate function for my api, but when I check the data.next in console.log there is no data in the first load but after adding few changes it works fine but still has an error when I refresh the page. Also, I noticed when I tried to console.log inside of function where the Axios or api declared, there's already a data in the first load of an application. Did anyone encounter this issue? Or my approach is wrong?
Here are my codes
/src/App.js
useEffect(async () => {
const res = await service.apiPokemon.fetchAll();
console.log(res.data.next)
}, []);
/src/api/pokemon.js
import axios from 'axios';
const URL = 'https://pokeapi.co/api/v2/pokemon';
export const fetchAll = async () => {
try {
const res = await axios.get(URL);
console.log(res.data.next);
return res;
} catch (error) {
console.log(error);
};
};
This is a very common problem. Your content is loaded before fetching the data. To solve this, you can add a condition to not render your content until you get the data:
let [pokemonsList, setPokemonsList] = useState([])
// Your useEffect hook to fetch data on mount
return (
{ pokemonsList.lenght > 0 && // If you are sure you'll receive pokemons
<div> {pokemonList.map((pokemon) => (
<p> {pokemon.name} </p>
)} </div>
}
)
Now, you'll only see the names of the pokemons when you have the list.
You can also add a loading message in case the response takes time with Redux and selectors.

How to return data with swr in react?

I try to display data and I use swr data fetching with react and here is the code :
import useSWR from "swr";
import axios from "axios";
const fetcherFunc = (...args) => {
return axios(...args).then((res) => console.log(res.data));
};
function MyComponent() {
const { data, error } = useSWR(
"https://jsonplaceholder.typicode.com/posts/",
fetcherFunc
);
if (error) return <div>failed to load</div>;
if (!data) return <div>loading...</div>;
return <div>{JSON.stringify(data)}</div>;
}
export default MyComponent;
The problem is that it's stuck in loading and the data won't get updated and is undefined also the console log of data in fetcher appears to work .
How to fetch data with swr in react and display fetched data ?
You're supposed to return res.data from fetcherFunc instead of console.log-ing data.
Also, just use url as the name of the argument for the fetcherFunc and pass that url to axios.get (don't use ...url spread operator on url). Take look at How To Use Axios for Data Fetching (passing the url, method, payload, etc).
Function for fetching the data should look like:
const fetcherFunc = (url) => axios.get(url).then((res) => res.data);
As for the useSWR hook, use it like this:
const { data, error } = useSWR("https://jsonplaceholder.typicode.com/posts/", fetcherFunc);

How to render something that is async in React?

I'm making a react app that works with a API that provides data to my App. In my data base I have data about pins on a map. I want to show the info of those pins on my react app, I want them to render. I get that information with axios and this url: http://warm-hamlet-63390.herokuapp.com/pin/list
I want to retrieve the info from that url, with axios.get(url), stringify the JSON data and then parse it to an array of pins.
The Problem:
My page will be rendered before I get the data back from the server, because axios is async, so I will not be able to show anything. UseEffect and useState won't work because I need something in the first place (I think).
What i've tried:
I tried to use useEffect and useState, but as I said, I think I need something in the first place to change it after. I also tried to use await, but await won't stop the whole React App until it has a response, although it would be nice if there is something that stops the app and waits until I have the array with the info so I can show it on the App then. I tried everything with async. I'm fairly new to React so there might be something basic i'm mssing (?). I've been on this for days, I can't get this to work by any means.. Any help, youtube videos, documentation, examples, is help. Anything. How the hell do I render something that needs to wait for the server respond?
My code:
//function that stores the data in the result array,
//but result array will only be available after the
//server response, and after the page is rendered
async function pin(){
const result = []
var url = "http://warm-hamlet-63390.herokuapp.com/pin/list"
const res = await axios.get(url)
console.log(res.data.data);
if(res.data){
const txt = JSON.stringify(res.data.data)
const result = JSON.parse(txt)
console.log(result);
}
return result;
}
class App extends React.Component{
render(){
return(
<div>
<Pin/>
<Mapa/>
</div>
)
}
}
export default App
I don't fully understand what you are trying to output but how you would usually handle this is with both the useState hook and the useEffect hook see example below.
//function that stores the data in the result array,
//but result array will only be available after the
//server response, and after the page is rendered
const pin = () => {
const [result, setResults] = useState([]);
var url = "http://warm-hamlet-63390.herokuapp.com/pin/list"
useEffect(() => {
//Attempt to retreive data
try {
const res = transformData();
if (res) {
// Add any data transformation
setResults(transformData(res))
}
else {
throw (error)
}
}
catch (error) {
//Handle error
}
}, [])
// Handle data transformation
const transformData = async () => {
const res = await axios.get(url)
const txt = JSON.stringify(res.data.data)
const result = JSON.parse(txt)
return result
}
if (!result) {
// Return something until the data is loaded (usually a loader)
return null
}
// Return whatever you would like to return after response succeeded
return <></>;
}
This is all assuming that Pin is a component like you have shown in your code, alternatively, the call can be moved up to the parent component and you can add an inline check like below to render the pin and pass some data to it.
{result && <Pin property={someData} />}
Just a bit of background the useEffect hook has an empty dependency array shown at the end "[]" this means it will only run once, then once the data has updated the state this will cause a rerender and the change should be visible in your component
Rest assured, useEffect() will work. You need to use a condition to conditionally render the content when it comes back from the server.
In the example below if results has a length < 1 the message Loading ... will be rendered in the containing <div>, once you're results are received the state will be updated (triggering a re-render) and the condition in the template will be evaluated again. This time though results will have a length > 1 so results will be rendered instead of Loading ...
I’m operating under the assumption that you’re function pin() is returning the results array.
const app = (props) => {
const [results, setResult] = useState([]);
React.useEffect(() => {
const getPin = async () => {
if (!results) {
const results = await pin();
setResult([…results])
}
}
getPin();
},[results]);
return (
<div>
{result.length ? result : 'Loading ... '}
</div>
)
}

fetch json data to state array

I fetch and get the data, I want to save it to state using setState as an array or object so I can call to each field in the return part and display it on screen
but I get this error:
Uncaught Error: Objects are not valid as a React child (found: object
with keys {gender, name, location, email, login, dob, registered,
phone, cell, id, picture, nat}). If you meant to render a collection
of children, use an array instead
import {useState} from 'react'
export default function Test(){
const [data, setData] = useState([]);
const getInfo = async () =>{
const response = await fetch('https://randomuser.me/api');
if(response.status === 200){
const res = await response.json();
setData(res.results[0]);
// also try this: setData(res)
// also try this: setData(res.result)
}else{
throw new Error('Unable to fetch data')
}
}
return(
<div>
<button onClick={() =>{getInfo()}}>fetch data</button>
{data}
</div>
)
}
Please have a look at this codesandbox URL, I feel you can make use of useEffect for your usecase link
The problem is your are getting an response which is not an array. You are trying to use higher order array methode on a object. Use ,
const resultArray = res.results;
get the array of results from the JSON.
It seems like res.results[0] is the object that has the keys of gender, name, location, email, login, dob, registered, phone, cell, id, picture, nat. But you are trying to set the state value data as an array.
You should set the data type to object.
In render function to browse the data, iterate the keys using Object.keys().
for the onClick triggering way in render, you don't need to () => {getInfo()} since there is no specific parameters passed to the method, just use onClick={getInfo}.
import {useState} from 'react'
export default function Test(){
const [data, setData] = useState({});
const getInfo = async () =>{
const response = await fetch('https://randomuser.me/api');
if(response.status === 200){
const res = await response.json();
setData(res.results[0]);
// also try this: setData(res)
// also try this: setData(res.result)
}else{
throw new Error('Unable to fetch data')
}
}
return(
<div>
<button onClick={getInfo}>fetch data</button>
{Object.keys.map(key => (<div>
{key} : {data.key}
</div>)}
</div>
)
}
The data being returned here from "https://randomuser.me/api" is not a simple JSON data. It is really a JSON object with multiple sub-objects in it such as "name", which is again having "title", "first" and "last" as sub-objects. This is the reason you are getting error that "found: object with keys".
If you are looking for dummy data for testing purpose, I would suggest you to check "https://jsonplaceholder.typicode.com/", which is a good source of dummy JSON data.
I have updated your code as under, which is returning data in proper JSON format and can be assigned to state.
const getInfo = async () =>{
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if(response.status === 200){
const res = await response.json();
console.log(res)
setData(res);
}else{
throw new Error('Unable to fetch data')
}
}
Your problem might be that you are using setData(res.results[0]);
I bet that this is an Object and not an Array.
const [data, setData] = useState([]);
states that the setData function only stores arrays.
try using
const [data, setData] = useState({});
and see if that is working
if it is not working give us the ouput of console.log(res.results)
and console.log(typeof(res.results[0]))

Categories

Resources