Mapping over array and rendering result - reactjs

I am having difficulties mapping over this object in order to render the data on the API.
Anyone has an idea of what I may be doing wrong?
class HomePage extends Component {
state = {
weatherResults: []
};
componentDidMount() {
let obj;
fetch(`http://api.openweathermap.org/data/2.5/forecast?
id=52490&appid=${API_KEY}&q=new%20york&cnt=2`)
.then(res => res.json())
.then(results => (obj = results))
.then(() => console.log(obj));
this.setState({
weatherResults: this.state.weatherResults
});
}
render() {
return (
<div>
{this.state.weatherResults &&
this.state.weatherResults.map(data => (
<div className="container">
<p>{data.city.name}</p>
</div>
))}
</div>
);
}
}
export default HomePage;

Since the fetch request is asynchronous, you want to use setState when the request has finished to put the response in the component state.
Looking at one of the sample requests of the API it looks like you get an object as response, which has city.name in it. Instead of having weatherResults be an array, you can set it to null initially and access city.name on it when the object has loaded.
Example
class HomePage extends Component {
state = {
weatherResults: null
};
componentDidMount() {
fetch(`http://api.openweathermap.org/data/2.5/forecast?id=52490&appid=${API_KEY}&q=new%20york&cnt=2`)
.then(res => res.json())
.then(results => {
this.setState({
weatherResults: results
});
})
.catch(error => console.error(error));
}
render() {
const { weatherResults } = this.state;
if (weatherResults === null) {
return null;
}
return (
<div>
<div className="container">
<p>{weatherResults.city.name}</p>
</div>
</div>
);
}
}

Related

code shows error when reading size of a variable

import React, { Component } from 'react';
import { render } from 'react-dom';
import Details from './Details';
import './index.css';
class App extends Component {
constructor() {
super();
this.state = {
usersData: [],
error: null,
selectedUser: null,
};
}
handleClick = (id) => {
const selectedUser = this.state.usersData.find(user => user.id === id)
this.setState(() => ({ selectedUser }))
}
findAlbum = (selectedUser, id) => {
fetch(`https://jsonplaceholder.typicode.com/users/${id}/albums`)
.then(response => response.json())
.then(data => {
selectedUser.albums = data;
})
.catch(err => this.setState({ error: err.message }))
}
setAlbum = (id) => {
const selectedUser = this.state.usersData.find(user => user.id === id)
this.findAlbum(selectedUser, id);
}
render() {
this.state.usersData.forEach(user => {
this.setAlbum(user.id)
})
const usersList = this.state.usersData.map(user => {
return <li key={user.id} onClick={() => this.handleClick(user.id)}>{user.name} {user.username} {user.email} {user.albums.size}</li>
})
return (
<>
<div className="UserList">
<h1>Users</h1>
<ul>{usersList}</ul>
</div>
<Details user={this.state.selectedUser} />
</>
);
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(data => {
this.setState({ usersData: data })
})
.catch(err => this.setState({ error: err.message }))
}
}
render(<App />, document.getElementById('root'));
When i am doing console.log selecteduser.albums inside findalbum function it is showing the data but when i did it in the li line it shows cant read size of undefined
i need to create a react app which shows list of users and their name username and email corresponding to each user we have albums we need to show album number also but i cant do it
is there any problem with pass by value or pass by reference in JS?
It's very wrong to update the state directly in react. Instead, use setState with a map and change anything related to a substate there. Also a tip, instead of passing the Id in the forEach and finding the user, just pass the user

Why can't I setState the data I've successfully in React?

So I'm new to React, and having trouble fetching API. I've successfully fetched data object(I've checked it with console.log(), but somehow cannot setState it. Please see the code below. It's my full code.
import React, { Component } from 'react';
import EachCake from './EachCake';
class Cake extends Component {
constructor(props){
super(props);
this.state = {
}
}
componentDidMount() {
this._fetchApiEachCake();
}
_renderEachCake = () => {
return <EachCake
image={this.cake_object.image}
source={this.cake_object.source}
body={this.cake_object.body}
/>
}
_fetchApiEachCake = () => {
return fetch("http://127.0.0.1:8000/api/cake/3")
.then((response) => response.json())
.then(data => console.log(data))
.then(data => this.setState({cake_object : data}))
// .catch((err) => console.log(err))
}
render() {
return (
<div>
{this.state.cake_object ? this._renderEachCake() : "Loading this cake"}
</div>
)
}
}
export default Cake
For some reason, all I get on the screen is "Loading this cake". What do you think is the problem?
import React, { Component } from 'react';
import EachCake from './EachCake';
class Cake extends Component {
constructor(props){
super(props);
this.state = {
// πŸ”₯ state initialization is optional also, useful for default values
}
}
componentDidMount() {
this._fetchApiEachCake();
}
_renderEachCake = () => {
return (
<EachCake
image={this.state.cake_object.image} // 🌟🌟
source={this.state.cake_object.source}
body={this.state.cake_object.body}
/>
)
}
_fetchApiEachCake = () => {
// πŸ”₯ you can also remove return here
return fetch("http://127.0.0.1:8000/api/cake/3")
.then((response) => response.json())
.then(data => console.log(data) || data) // 🌟
.then(data => this.setState({cake_object : data}))
// .catch((err) => console.log(err))
}
render() {
return (
<div>
{this.state.cake_object ? this._renderEachCake() : "Loading this cake"}
</div>
)
}
}
export default Cake
🌟🌟 must be grabbed from the state not directly from this reference.
🌟 console.log doesn't return anything, so you must return data yourself oΩ‚ combine setState and logging step both in one step e.g.
.then(cake_object => console.log(cake_object) || this.setState({ cake_object }))
The then() method returns a Promise.
if you are trying to check if the data is loaded or not you should use the callback this.setstate({key: value}, () => {//do something})
you can use this to set a flag whether data has been loaded into state or not. and i also think that you should initialize that cake_object to null.
so after that your code would be like:
this.state = {
loaded: false,
cake_object: null
}
_fetchApiEachCake = () => {
return fetch("http://127.0.0.1:8000/api/cake/3")
.then((response) => response.json())
.then(data => console.log(data))
.then(data => this.setState({cake_object : data}, () => {
console.log(this.state.cake_object);
this.setState({loaded: true});
}))
// .catch((err) => console.log(err))
}
render() {
return (
<div>
{this.state.loaded ? this._renderEachCake() : "Loading this cake"}
</div>
)
}
2 changes :
1.
this.state = {
cake_object:null,
}
_fetchApiEachCake = () => {
return fetch("http://127.0.0.1:8000/api/cake/3")
.then((response) => response.json())
.then((data) => {
console.log(data)
this.setState({cake_object : data})
})
// .catch((err) => console.log(err))
}
Hopefully it works!

React How to fetch data from mutiple urls

From Starships I get only array of urls I would like to fetch these url adresses and get name of each starship. I tried to do it throuht map array but I probably donΒ΄t know to write it. Do you have any ideas?
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props){
super(props);
this.state = {
movies:[],
starships:[],
}
}
//we fetch all data and store it to movies
async componentDidMount() {
return await fetch("https://swapi.dev/api/films/")
.then(result => result.json())
.then(data =>
this.setState({
movies: data.results
})
)
}
render(){
console.log(this.state.movies);
return (
<div className="App">
<h1>Movies</h1>
<div className="moviesList">
{this.state.movies.map((movie, index) => {
return <p key={index} >{movie.title}</p>
})}
</div>
<div className="starshipsList">
{this.state.movies.map((starship, index) => {
return <p key={index} >{starship.starships}</p>
})}
</div>
</div>
);
}
}
export default App;
You should check if the API doesn't provide another endpoint for starships as what are you trying to do isn't a best approach in my opinion.
But if it doesn't and you still need starship list, something like this could work:
async componentDidMount() {
// get movies
const moviesResult = await fetch("https://swapi.dev/api/films/");
const movies = await moviesResult.json();
// get array of all urls
const starshipsUrls = movies.results.reduce((acc, movie) => {
return acc.concat(movie.starships);
},[]);
// map over the urls and use promise.all to fetch
const starshipsResult = await Promise.all(starshipsUrls.map(url=> fetch(url)));
const starships = starshipsResult.json();
this.setState({
movies,
starships
});
}

state becomes undefined after async call

Trying to understand why the component's state is becoming undefined.
Before the async call the console shows this.state.pubsubtopics as [], after the call it becomes undefined
code:
class PubSubTopics extends React.Component{
constructor(props){
super(props);
this.state = {
pubsubtopics: [],
};
}
componentDidMount() {
console.log('after component mounted');
console.log(this.state.pubsubtopics);
this.callBackEndAPI()
.then(res =>
this.setState({pubsubtopics: res.express}))
.catch(err => console.log(err));
console.log('after setting state');
console.log(this.state.pubsubtopics);
}
callBackEndAPI = async () => {
const response = await fetch('/listtopics');
const body = await response.json();
if(response.status !== 200){
throw Error(body.message)
}
return body;
}
handlePrintStateClick = () => {
console.log(this.state.pubsubtopics);
}
render(){
return(
<div>
<ul>
</ul>
<button onClick={this.handlePrintStateClick}>printState</button>
</div>
)
}
}
Logs (last log entry is from clicking the button):
after component mounted
index.js:16 []
index.js:21 after setting state
index.js:22 []
index.js:36 undefined
res.express didn't exist in the server's response, using res.topics solved the problem

React, data display with GitHub api

I am trying to display a list of user repositories. Through the spread operator attempts to spell the object. However, I do not know if this is a good method, there are no errors in the console, but nothing appears on the screen. This is my code.
class ItemUserDetail extends React.Component {
constructor() {
super();
this.state = {
usersRepos: []
};
}
componentDidMount() {
const { user } = this.props.match.params;
const url = `https://api.github.com/users/${user}/repos`;
fetch(url)
.then(res => res.json())
.then(json => this.setState({ usersRepos: json }));
}
render() {
const Repos = this.state.usersRepos ? { ...this.state.usersRepos } : null;
return (
<div>
<p>{Repos.name}</p>
</div>
);
}
}
export default ItemUserDetail;
Since you are returning an array of repositories, your render method should look like this
render() {
const Repos = this.state.usersRepos ? this.state.usersRepos : null; // you don't need this
const { userRepos } = this.state; // destructure
return (
<div>
{userRepos.map(repo => <p key={repo.id}>{repo.name}</p>)}
</div>
);
}

Resources