Issue with API GET response format - arrays

I am making a get request to an api and then trying to map over the request. My issue is that the response is changing from data in this usual [{...},{...}] to '[[Object Object][Object Object]]' so that when I try to map over the array, it is throwing an error. I have tried using JSON.stringify() but it does not work. Here is my code:
---- Home.js
import React, { useState, useEffect } from "react";
const Home = () => {
const [tableData, setTableData] = useState([]);
useEffect(() => {
const url =
"https://api.football-data.org/v2/competitions/2021/standings?standingType=HOME";
const fetchItems = async () => {
const apiResult = await fetch(url, {
headers: {
"X-Auth-Token": process.env.REACT_APP_API_KEY,
},
})
.then((res) => res.json())
.catch((err) => console.error(err));
setTableData(apiResult.standings[0].table);
};
fetchItems();
}, []);
return (
<div className="home-container">
<Hero />
<Table data={tableData} />
<Predictions />
<Footer />
</div>
);
};
------ Table.js
import TableList from "./TableList";
const Table = ({ data }) => {
return (
<section className="table" id="table">
<h1 className="table-header">Table</h1>
<div className="table-container">
<TableList data={data} />
</div>
</section>
);
};
--------- TableList.js
import TableCard from "./TableCard";
const TableList = ({ data }) => {
return (
<div className="table-list">
{data.map((index, teamData) => {
return <TableCard key={index} data={teamData} />;
})}
</div>
);
};
If I console log the mapped data, I get '0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20',
instead of the data that I initially receive in the fetch request that is [{position:1, team: {...}, gamesPlayed:9}, {...}].
I have never had this issue before when using a GET request to an API so any and all help is appreciated. Sorry in advance for the poor formatting.

Related

Custom useFetch hook React not working with errors

so i'm trying to implement a custom react hook for fetch. It's working fine, but i can't seem to do it with the errors. if i try to display the error in a custom component it's says object is not a valid React child ... okey i know that, but how then it's working when there's no error in the componenet ? Here's the code:
Hook:
import { useEffect, useState } from "react";
const useFetch = (url) => {
const [data, setData] = useState([]);
const [error, setError] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
fetch(url, { signal: signal })
.then(res => res.json())
.then(result => {
setData([result]);
})
.catch(err => {
setError(true);
setErrorMessage(err);
})
return () => {
setError(false);
controller.abort();
};
}, [url]);
return { data, error, errorMessage };
};
export default useFetch;
Component:
const WeatherNow = () => {
const { city } = useContext(CityContext);
import ErrorHandler from '../error-component/ErrorHandler';
const { data, error, errorMessage } = useFetch(`https://api.weatherapi.com/v1/forecast.json?key=${process.env.REACT_APP_API_KEY}&q=${city}&aqi=no`);
if (error) {
return <>
<ErrorHandler props={errorMessage} />
</>
};
return (
<>
{data && data.map(x => (
<div className="today-forecast" key={city}>
<h4>
{city}
</h4>
<div>
{x.current.condition.text}
</div>
<div>
<img src={x.current.condition.icon} alt='' />
</div>
<h3>
{x.current.feelslike_c} *C
</h3>
<h5 className='rain-wind'>
Rain: {x.current.precip_in} % / Wind: {x.current.wind_kph} km/h
</h5>
<div className='links'>
<Link to='/hourly'>Hourly</Link> <Link to='/daily'>Daily</Link>
</div>
</div>
))}
</>
);
};
The ErrorHandler:
import './ErrorHandler.css';
import error from './error.png';
const ErrorHandler = ({ props }) => {
return (
<div className="error-component">
<div>
<h4>
{props}
</h4>
</div>
<div>
<img src={error} />
</div>
</div>
);
};
export default ErrorHandler;
Because of the catch (err) is an unknown type, it might return anything and more likely an object with a message key.
Try to change the way you are setting the error message and make sure it’s a string:
setErrorMessage(typeof err?.message === "string" ? err.message : "Unknown Error");
Warning
Using process.env.REACT_APP_API_KEY in client side is not safe at all.
The problem is in the catch block , somehow the err is inpromise and i can't use it

results.map is not a function (Consider adding an error boundary to your tree to customize error handling behavior.)

I have this what may seem like a simple problem for more experienced developers but it has been irritating me for quite a while.
I keep having .map is not a function, although it clearly is. see the code below
I am iterating over the results state, but it doesn't seem to work
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<App.js>>>>>>>>>>>>>>>>>>>>>>>>>>>>
import "./App.css";
import React, { useEffect, useState } from "react";
import ContactCard from "./ContactCard";
const App = () => {
const [results, setResults] = useState([]);
useEffect(() => {
fetch("https://randomuser.me/api/?results=5")
.then((response) => response.json())
.then((data) => {
console.log(data);
setResults(data);
});
}, []);
return (
<div>
{results.map((result, i) => {
return (
<ContactCard
key={i}
avatarUrl={result.picture.large}
name={result.name}
email={result.email}
age={result.dob.age}
/>
);
})}
</div>
);
};
export default App;
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>
import React, { useState } from "react";
const ContactCard = (props) => {
const [showAge, setShowAge] = useState(false);
const showAgefn=()=>{
setShowAge(!showAge)
}
return (
<div className="contact-card">
<img src={props.avatarUrl} alt="profile" />
<div className="user-details">
<p>Name: {props.name}</p>
<p>Email: {props.email}</p>
<button onClick={showAgefn}>Show age</button>
{showAge && <p>Age: {props.age}</p>}
</div>
</div>
);
};
export default ContactCard;
Try this
{results.results.map((result, i) => {
return (
<ContactCard
key={i}
avatarUrl={result.picture.large}
name={result.name}
email={result.email}
age={result.dob.age}
/>
);
}
i prefer to rename my state to [data, setData] then I can use data.results instead of results.results
This issue is that the response you are getting from https://randomuser.me/api/?results=5 is like as follows
{
"results": [...],
"info": {...}
}
So in your useEffect just modify the following
useEffect(() => {
fetch("https://randomuser.me/api/?results=5")
.then((response) => response.json())
.then((data) => {
console.log(data);
setResults(data.results); // Just modify this line
});
}, []);
All Other things are perfectly fine
Hope it Helps
First results keyword is the state and Second results keyword is for the array.
Don't Forget to use ?.map as if the map is null it won't return any error. It's a check if there is any data in map or not.
{results.results?.map((result, i) => {
return (
<ContactCard
key={i}
avatarUrl={result.picture.large}
name={result.name}
email={result.email}
age={result.dob.age}
/>
);
}
Saving the state like so [users, setUsers]
Then adding Array.from inside the curly brackets seem to have solved the issue
return (
<div>
{Array.from(users.map((user, i) => {
return (
<ContactCard
key={i}
avatarUrl={user.picture.large}
name={user.first}
email={user.email}
age={user.dob.age}
/>
);
}))}
</div>
);

How to interpolate an image src in React?

I am trying to display a photo from an object I received from an API. I was able to get down to the data information, but the image is not displaying in the displayPhoto function. I was wondering what was wrong with this?
import React, { useState, useEffect } from "react";
import axios from "axios";
// fetch api
// display data
// display more data
export default function App() {
const [data, setData] = useState([]);
const fetchAPI = () => {
axios.get('https://randomuser.me/api')
.then(res => {
// handle success
console.log(res["data"]["results"]);
const indData = (res["data"]["results"]);
const updatedData = [
...data,
...indData
]
setData(updatedData);
// console.log(data)
})
.catch(error => {
// handle error
console.log(error);
})
}
const mapData = (info) => {
const first = (info["name"]["first"])
const last = (info["name"]["last"])
return `${first} ${last}`;
}
const displayPhoto = (info) => {
const picture = (info["picture"]["large"]);
return <img src={picture} />;
}
return (
<>
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={fetchAPI} >Fetch API </button>
{data.map((e, idx) => (
<p>{mapData(e, idx)}</p>
{displayPhoto(e)}
))}
</div>
</>
);
}
It looks like you put the wrong src to img tag in displayPhoto function. You should check the path and then render img component with it.
{data.map((e, idx) => (
<div>
<p>{mapData(data, idx)}</p>
<img src={data.rightSrcl} />
</div>
))}

I keep getting an error: "TypeError: countries.map is not a function"

I keep getting
TypeError: countries.map is not a function
and I cannot figure out why. When I use comment out the <Table /> and use console.log(tableData), it shows up with the correct array of countries, however when I include the <Table /> I do not get the arrays.
Any help would be appreciated!
import React, {useState, useEffect} from 'react';
import {
MenuItem,
FormControl,
Select,
Card,
CardContent
} from "#material-ui/core";
import InfoBox from "./InfoBox";
import Map from "./Map";
import './App.css';
import Table from "./Table";
function App() {
const [countries, setCountries] = useState([]);
const [country, setCountry] = useState(["worldwide"]);
const [countryInfo, setCountryInfo] = useState({});
const [tableData, setTableData] = useState({});
useEffect(() => {
fetch('https://disease.sh/v3/covid-19/all')
.then(response => response.json())
.then((data) => {
setCountryInfo(data);
})
}, []);
useEffect(() => {
const getCountriesData = async () => {
await fetch("https://disease.sh/v3/covid-19/countries")
.then((response) => response.json())
.then((data) => {
const countries = data.map((country) => (
{
name: country.country,
value: country.countryInfo.iso2
}
));
setTableData(data);
setCountries(countries);
});
};
getCountriesData();
}, []);
const onCountryChange = async (event) => {
const countryCode = event.target.value;
const url = countryCode === 'worldwide' ? 'https://disease.sh/v3/covid-19/all' : `https://disease.sh/v3/covid-19/countries/${countryCode}`;
await fetch(url)
.then(response => response.json())
.then(data => {
setCountry(countryCode);
//All data from country
setCountryInfo(data);
})
};
console.log('COUNTRY INFO >>>', countryInfo);
return (
<div className="app">
<div className="app__left">
<div className="app__header">
<h1>COVID-19 STATS</h1>
<FormControl className="app__dropdown">
<Select variant="outlined" onChange={onCountryChange} value={country}>
<MenuItem value="worldwide">Worldwide</MenuItem>
{
countries.map((country) => (
<MenuItem value={country.value}>{country.name}</MenuItem>
))
}
</Select>
</FormControl>
</div>
<div className="app__stats">
<InfoBox title="COVID-19 Cases" cases={countryInfo.todayCases} total={countryInfo.cases} />
<InfoBox title="Recovered" cases={countryInfo.todayRecovered} total={countryInfo.recovered}/>
<InfoBox title="Deaths" cases={countryInfo.todayDeaths} total={countryInfo.deaths} />
</div>
<Map />
</div>
<Card className="app__right">
<CardContent>
<h3>Live cases per country</h3>
{console.log(tableData)}
<Table countries={tableData} />
<h3>Worldwide new cases</h3>
</CardContent>
</Card>
</div>
);
}
export default App;
Here is the Table.js file:
import React from 'react'
function Table({ countries }) {
return <div className="table">
{countries.map(({ country, cases }) => (
<tr>
<td>{country}</td>
<td>{cases}</td>
</tr>
))}
</div>
}
export default Table
Looks like const [tableData, setTableData] = useState({});, you're setting tableData as an object.
Also, the API results with data which is an object and is tableData is set as an object again
setTableData(data);
When using <Table countries={tableData} /> component tableData is an object and not an array.
Check the sort function used you must have returned something wrong
export const sortData = (data) => {
const sortedData = [...data]; //copy the data to sortedData
sortedData.sort((a, b) => {
if (a.cases > b.cases) {
return -1;
} else {
return 1;
}
});
return sortedData;
};
You can also add check if countries exists.
countries && countries.map(({ country, cases }) => {}

How could I display in my front a back request?

I've created my backend and it works. I tested different Axios requests in order to create a form.
In my React front project, I created a POST axios request, I console.log(response.data) and I got an object with the id, the title and questions.
I am stuck because I don't know how I could display the data of the object in my front.
Here is my front React code:
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
const NewForm = () => {
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
if (data.length === 0) {
const response = await axios.post(
"https://back-formnest-lereacteur.herokuapp.com/form/create",
{
title: "Your event",
}
);
console.log(response.data);
setData(response.data);
}
};
fetchData();
}, [data]);
return (
I am completely stuck here to display the data of my backend in my front
This is my backend code:
const express = require("express");
const router = express.Router();
const Form = require("../models/Form");
router.post("/form/create", async (req, res) => {
try {
if (req.fields.title) {
const newForm = new Form({
title: req.fields.title,
});
await newForm.save();
return res.json(newForm);
} else {
return res.status(400).json({ error: "Missing parameters" });
}
} catch (e) {
return res.status(400).json({ error: e.message });
}
});
This is my console.log(response.data) I want to display in my front React page:
I edited my code and I got an error:
import React, { useState, useEffect } from "react";
/* import { Link } from "react-router-dom"; */
import axios from "axios";
const NewForm = () => {
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
if (data.length === 0) {
const response = await axios.post(
"https://back.herokuapp.com/form/create",
{
title: "Nouveau formulaire",
}
);
console.log(response.data);
setData(response.data);
}
};
fetchData();
}, [data]);
return (
<>
<div>My forms</div>
<div>
{data && (
<>
<p>{data.title}</p>
{data.questions.map((question, index) => (
<div> {question} </div>
))}
</>
)}
</div>
</>
);
};
export default NewForm;
Hi Guys,
I updated my code but I have still an error code (TypeError: Cannot read property 'length' of undefined)
<>
<div>My forms</div>
<div>
{data && (
<>
<p>{data.title}</p>
{data.questions.length &
data.questions.map((question, index) => {
return <p key={index}>{question}</p>;
})}
</>
)}
</div>
</>
I updated again my code, I succeeded only to display the title of my form but I did not succeed to display the data included in my question array. I have a "0" which appears instead of my data. Please help
return (
<>
<div>My forms </div>
<div>
{data && data.questions && (
<>
<div>{data.title} </div>
{data.questions.length &
data.questions.map((question, index) => {
return <p key={index}>{question}</p>;
})}
</>
)}
</div>
</>
I updated again, same error appears:
return (
<>
<div>My forms </div>
<div>
{data &&
data.questions &&
data.questions.length(
<>
<div>{data.title} </div>
{data.questions.map((question, index) => {
return <p key={index}>{question}</p>;
})}
</>
)}
</div>
you've done the hard part!
now just .map over the question array if you want to display them out?
<div>
{data.questions.map((question => (
<div> {question.title} </div>
))}
</div>
I've only done a simple example but of course you can display as much or as little as you want
of course anything in state you can render. so if you want to display title do:
{data.title} wherever pleases you
It looks like your backend responds with an object, so here is how you could go about it.
1) Change your initinal state to undefined like this.
const [data, setData] = useState([]);
to
const [data, setData] = useState(undefined);
Then you can use it in the display like this
return (
<div>
{data && (
<>
<p>{data._id}</p>
<p>{data.title}</p>
{data.question.length && data.question.map((question,idx) => {
// this is assuming that each question is just a string and not an object
return (<p key={idx}>{question}</p>)
})}
</>
)}
</div>
)

Resources