fetch json data to state array - javascript

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]))

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>
);
}

ReactJS call function once if query strings set

Explain:
In useEffect I get products via getProducts() function based on given data and data contains search filters and will be update by user so need to watch it in realtime, for example data contains an object like this {brand: 'x'}
const [data, setData] = useState({});
useEffect(() => {
getProducts(data) // get products via api based on data, if data is clear, it will return all products
.then(data => {
//
});
}, [data]) // watch data in realtime and send it to getProducts()
useEffect(() => {
getQuery(); // check if there are search querys
}, [])
Also there is a getQuery() function, it will check if there are any query strings in search params when page is reload, and will get query strings and set it to data, and by above code if data get update it will call getProducts() again, actually it update products.
const getQuery = () => {
let obj_url = new URL(window.location.href);
let params = obj_url.searchParams;
let searchParams = new URLSearchParams(params);
// some other code
setData(obj); // get query and set it to data
}
Problem:
I noticed while there are query strings in url it will call getProducts() twice! well this code definitely does that, but I don't want it, how can I prevent to call this twice? I just want if there are query strings call once, if not call once.
Yes, it will call it once for the initialization of useState, and second time for the updated data from getQuery on the useEffect. You don't really need a useEffect for the getQuery function. You can just set the data from query on the initial state directly (the initial state will only be set on the initial render anyway, not on subsequent ones).
const [data, setData] = useState(getQuery());
useEffect(() => {
getProducts(data) // get products via api based on data, if data is clear, it will return all products
.then(data => {
//
});
}, [data]) // watch data in realtime and send it to getProducts()
const getQuery = () => {
let obj_url = new URL(window.location.href);
let params = obj_url.searchParams;
let searchParams = new URLSearchParams(params);
// some other code
return obj ?? {}
}
Bad idea to use that function in state initialization, you can do this with native way, react-router-dom. Based on #Cristian-Florin Calina answer, I provide new answer:
import { useRouter } from 'next/router';
const Router = useRouter();
const [data, setData] = useState(Router.query);
useEffect(() => {
getProducts(data)
.then(data => {
//
});
}, [data]);
Router.query return all search params and with this there is no need to call getQuery function. easy!

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.

Trying to store FireStore array in React Native?

I have been trying to push or store a FireStore array in one of my own arrays. I have tried a few versions of code, the first being this:
var data = [];
db.collection('Rooms')
.doc(code)
.get()
.then((docs) => data.push(docs.data()));
However, when I log the data variable, it comes out as an empty array. The second method I have tried is this:
var [data, setData] = useState([]);
db.collection("Rooms")
.doc(code)
.get()
.then((docs) => setData(docs.data()));
However this method seems to setData infinitely, so it is reading into my API infinitely, which I would like to avoid. The last method I tried was this:
var data = db.collection("Rooms").doc(code).get();
console.log(data);
But this just returns
Promise {
"_U": 0,
"_V": 0,
"_W": null,
"_X": null,
}
Could anyone help me with this, ideally I'd like to store the data of an array called "MovieArray" inside the document, but I can't even access the document, so even if you can just help me store the data of the whole document, it would be very helpful.
If you are using react, I would suggest using the hook. You also, don't really need to push objects to an array like that.
Here is an example of how to get some data and store the collection of data.
const Forum = () => {
const [posts, setPosts] = useState(null);
const collectIdsAndDocs = (doc) => {
return { id: doc.id, ...doc.data() };
};
useEffect(() => {
const getPost = async () => {
const snapshot = await firestore.collection('Posts').get();
const myPosts = snapshot.docs.map(collectIdsAndDocs);
console.log(myPosts);
setPosts({ myPosts });
};
const createPost = async (post) => {
const docRef = await firestore.collection('Posts').add(post);
const doc = await docRef.get();
console.log(doc);
};
createPost({ Title: 'My First Post', Content: 'My content' });
getPost();
}, []);
return (
// return some JSX
);
};
Why does this work?
When you get a collection, Firebase returns a snapshot of the collection.
This snapshot has a list of docs or an array if you will.
We then want to map over those docs constructing a new object that contains just the document data and the ID of individual doc. This is what the myPosts variable is.
Using the react state hook, you can set that object to the current state of Posts, in your case this would be rooms.
When you add something to the database, Firestore will return a reference to the newly added item. You can then call get() to get the document back if you need it.
Try changing to (see comment before this)
const [data, setData] = useState({});

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

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

Categories

Resources