I'm not sure what I'm doing wrong or what I'm missing but I can't iterate over my array of objects when I do my get request. I get the results on my console but they don't appear on the page unless I call one individual item. It only happens when I'm using React, I have also tried with JSON placeholder fake APIs and get the same result. Is there anything in React that stops this iteration to be executed? Thank you so much for your help!
import React, { Component } from 'react';
class UserList extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
isLoaded: false,
};
}
componentDidMount() {
this.loadData();
}
loadData = async () => {
const response = await fetch('http://dev.pubmate.io/pubmate/api/0.1/user/all');
if (response) {
const allusers = await response.json();
console.log(response);
console.log(allusers);
console.log(allusers[0].email);
this.setState({
isLoaded: true,
users: [...allusers],
});
}
};
render() {
let { isLoaded, users } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="userlist">
Data is been loaded
<ul>
{users.map((user) => {
<li key={user.id}>{user.title}</li>;
})}
</ul>
</div>
);
}
}
}
export default UserList;
You were quite close, but just need to slightly adjust your loop.
The simplest change would be to swap:
<ul>
{users.map(user => {
<li key={user.id}>
{user.title}
</li>
})}
</ul>
for
<ul>
{users.map(user => ( // <--- "{" becomes "("
<li key={user.id}>
{user.title}
</li>
))} // <--- "}" becomes ")"
</ul>
This will return an element to be rendered
Related
I have a simple fetch call, that maps the data from the state being passed to the state via fetch. I would like to take only a particular object from the items array. By index I suppose. And display its contents. Basically I do not want to loop out all the data. Instead I would like to control when that data gets displayed. like items[0].name and items[0].email or something like that.
Here is my code and a link to a codesandbox for ease of help
import React, { Component } from "react";
import ReactDOM from "react-dom";
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
isLoaded: false
};
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json
});
});
}
render() {
var { isLoaded, items } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="App">
<ul>
{items.map(item => (
<li key={item.id}>
Name: {item.name} | Email: {item.email}
</li>
))}
</ul>
</div>
);
}
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You can select the value from array using index and then display the properties you want to show on UI,
Here i am having a property in state named index which is having default value 0, now on the based on index we select the element from items array and display it's value
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
isLoaded: false,
index: 0
};
this.handleIndex = this.handleIndex.bind(this)
}
handleIndex(event){
this.setState({index: event.target.value})
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json
});
});
}
render() {
var { isLoaded, items, index } = this.state;
const selected = items [index] || items[0]
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="App">
<ul>
<li key={selected.id}>
Name: {selected.name} | Email: {selected.email}
</li>
</ul>
<input type='number' onChange={(e)=>this.handleIndex(e)} placeholder='Enter a valid index'/>
</div>
);
}
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<body>
<div id='root'/>
</body>
If you need to find index based on certain condition then you need to use findIndex or also you can use find to get required element from array and then display the values, in case of multiple element can fulfill the condition then you can filter the values first and thenmap` over them
Loading in an API and I'm getting .map isn't a function. Been looking through every example and followed them exactly but still getting this error. The error is of course happening at the .map in the ul tag
class Login extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
isLoaded: false
};
}
componentDidMount() {
fetch(
"https://opentdb.com/api.php?amount=10&category=18&difficulty=easy&type=boolean"
)
.then(res => res.json())
.then(json => {
this.setState({ isLoaded: true, items: json });
});
}
render() {
var { isLoaded, items } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="App">
<ul>
{items.map(item => (
<li key={item.results.question}>{item.results.question}</li>
))}
</ul>
</div>
);
}
}
}
export default Login;
Your actual data is coming in json.results, so you need to set json.results in state like,
this.setState({ isLoaded: true, items: json.results });
You need to iterate array like,
{ items.map(item => (
<li key={item.question}>{item.question}</li>
))}
Demo
I have created a menu, with a submenu and a third child. So far I had it done simply with a json in local const data that is now commented. I need that from now on the data is collected from my json but I do not know how to do it. As it is now I get the following error: 'data' is not defined ( in my render)
class Nav extends Component {
constructor(props){
super(props)
this.state = {
navigation:[]
}
}
componentWillMount() {
fetch('json_menuFIN.php')
.then(response => response.json())
.then(data =>{
this.setState({navigation: data });
console.log( data)
})
}
render(){
const { data = null } = this.state.navigation;
if ( this.state.navigation && !this.state.navigation.length ) { // or wherever your data may be
return null;
}
return (
<Menu data={this.state.navigation}/>
)
}
}
const renderMenu = items => {
return <ul>
{ items.map(i => {
return <li>
<a href={i.link}>{ i.title }</a>
{ i.menu && renderMenu(i.menu) }
</li>
})}
</ul>
}
const Menu = ({ data }) => {
return <nav>
<h2>{ data.title }</h2>
{ renderMenu(data.menu) }
</nav>
}
I do not know what else to do to make it work with what I have. Thank you very much for the help.
Your navigation property in state has no title and menu properties, so you pass an empty array to Menu component. That's why you have an error Cannot read property 'map' of undefined. You should change your state initialization in constructor.
class Nav extends Component {
constructor(props){
super(props);
this.state = {
navigation: {//<-- change an empty array to object with a structure like a response from the server
menu: [],
title: ''
}
}
}
//...
render(){
return (
<Menu data={this.state.navigation} />
)
}
}
Don't use componentWillMount as it is deprecated and will soon disappear, the correct way is to use componentDidMount method along with a state variable and a test in your render.
this.state = {
navigation: [],
init: false
}
componentDidMount() {
fetch('json_menuFIN.php')
.then(response => response.json())
.then(data => {
this.setState({ navigation: data, init: true });
console.log( data)
})
}
Also, you cannot extract the data variable from your navigation variable in the state, navigation has been defined with your data response, so use it directly.
render() {
const { navigation, init } = this.state;
if(!init) return null
return (
<Menu data={navigation}/>
)
}
I assume that navigation is always an array, whatever you do with it.
I've been trying to make this work for hours now. Whenever I run the code it keeps giving me a "Line 28: Expected an assignment or function call and instead saw an expression" error.
import React from "react";
class Brewery extends React.Component {
constructor(props) {
super(props);
this.state = {
breweries: []
};
}
componentDidMount() {
fetch("https://api.openbrewerydb.org/breweries")
.then(response => response.json())
.then((data) => {
this.setState({
breweries: data,
})
})
}
render() {
const { breweries } = this.state;
return(
<ul>
{breweries.map((brewery) => {
<li key={brewery.id}>
{brewery.name}
</li>
})}
</ul>
)
}
}
export default Brewery;
It is probably you are not returning anything in your .map method.
<ul>
{breweries.map(brewery => {
<li key={brewery.id}>{brewery.name}</li>;
})}
</ul>
Here, you are using fat arrow function with a body block but not using return, so add it:
<ul>
{breweries.map(brewery => {
return <li key={brewery.id}>{brewery.name}</li>;
})}
</ul>
or use implicit return:
<ul>
{breweries.map(brewery => (
<li key={brewery.id}>{brewery.name}</li>
))}
</ul>
I'm trying to render a list of titles from Chrome's topSites api for a chrome extension.
When I log it to the console I get this:
[
{
"title": "Chrome Web Store",
"url": "https://chrome.google.com/webstore?hl=en"
}
]
However, the following doesn't render anything to the page
render() {
return (
<ul>
{
chrome.topSites.get(data => {
console.log(data);
data.map(site => {
return (
<li key={site.title}>
{site.title}
</li>
);
});
})
}
</ul>
);
}
Expected output:
A p tag with the title of the site gets rendered to the screen
Actual output:
Nothing is rendered on screen
This ended up working for me. Moving chrome.topSites.get intocomponendDidMount()and assigning it to state. Then mapping thethis.state.sites` to the page in the render method.
export default class TopSites extends Component {
constructor(props) {
super(props);
this.state = {
sites: [],
}
}
componentDidMount() {
chrome.topSites.get(data => {
this.setState({
sites: data
});
});
}
render() {
const {sites} = this.state;
return (
<ul>
{sites.map(site => {
return (
<li key={site.title}>
{site.title}
</li>
);
})}
</ul>
);
}
}
state= {
data: '',
}
// declaring a async function
getData = async () => {
const result = await chrome.topSites.get(); // waiting for the result
this.setState({ data: result});
}
componentDidMount(){
this.getData();
}
render(){
const list = this.state.data ? this.state.data.map((val) => <li key={val.title}> {val.title}
</li> : null)
return(
<ul>
{list}
</ul>
)
}