Child component does not render properly - html

In my code, the parent component is Bucket.js and the child component is the ListItem.js. The parent component makes a call to the db and gets back an object that has a structure of: [{...},{...},{...}], which will be stored into this.state.search.
When I render each child component, only the first <div> tag in <ListItem> displays. Everything after that does not render, I cannot figure out why that is the case.
Bucket.js
import React, { Component, useState } from "react";
import axios from "axios";
import ListItem from "./ListItem";
class Bucket extends Component {
constructor() {
super();
this.state = {
search: [],
};
}
componentDidMount() {
axios
.get(`http://localhost:9000/viewCribb`)
.then((response) => response)
.then((result) => {
this.setState({ search: result.data });
console.log("Search State: ", this.state);
});
}
render() {
{
console.log("Rendering!");
}
return (
<>
{this.state.search ? (
<>
{Object.keys(this.state.search).map((item, index) => (
<ListItem
{...this.props}
key={this.state.search[item].address_id}
listing={this.state.search[item]}
></ListItem>
))}
</>
) : (
<></>
)}
</>
);
}
}
export default Bucket;
ListItem.js
import React from "react";
import classNames from "classnames";
const ListItem = (...props) => {
console.log("props", props);
return (
<>
<div>{props[0].listing.streetaddress}</div>
<div className="tiles-item reveal-from-right" data-reveal-delay="200">
<div className="tiles-item-inner">
<div className="testimonial-item-content">
<p className="text-sm mb-0">{props[0].listing.streetaddress}</p>
</div>
<div className="testimonial-item-footer text-xs mt-32 mb-0 has-top-divider">
<span className="testimonial-item-name text-color-high">
Roman Level
</span>
<span className="text-color-low"> / </span>
<span className="testimonial-item-link">
<div href="#0">AppName</div>
</span>
</div>
</div>
</div>
</>
);
};
export default ListItem;

According to:
https://www.npmjs.com/package/react-axios
https://github.com/axios/axios
this might be wrong:
componentDidMount() {
axios
.get(`http://localhost:9000/viewCribb`)
.then((response) => response)
.then((result) => {
this.setState({ search: result.data });
console.log("Search State: ", this.state);
});
}
the existence of two .then to get the response feels wrong.
It seems you are following the pattern mentioned at:
https://www.digitalocean.com/community/tutorials/react-rendering-arrays-in-react
It might be a good idea if you could share the data returned through the response and compare its structure to see it it fits your needs

The problem had to do with my css, it did not get imported properly

Related

Passing props in react - fetching

I'm simply trying to pass props through components and render it in jsx but somehow that wouldn't work. I was searching for the problem but just cannot find it.
I'm trying pass props from this component:
import React from "react";
import "../styles/Products.css";
import ProductItem from "../items/ProductItem";
class Products extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentDidMount() {
fetch("../products.json")
.then(response => response.json())
.then(response => this.setState({ data: response.products }));
}
render() {
return (
<div className="products-container">
<ProductItem data={this.state.data[0]} />
</div>
);
}
}
export default Products;
to this component:
import React from "react";
import "../styles/ProductItem.css";
const ProductItem = props => {
console.log(props.data, "current");
return (
<div className="product-item">
<img src="" alt="" className="bike-image" />
<div className="active-product" />
<div className="view-details">Compare</div>
<h2>Bike</h2>
<h4>downhill bike</h4>
<p>3500 PLN</p>
</div>
);
};
export default ProductItem;
And the problem is when I'm looking in my react dev tools, props has passed properly, but when I'm trying to get to attributes of the object like props.data.id, I get an error:
Cannot read property 'id' of undefined
fetch needs some time to get the response and populate the this.state.data array. So you need to check if the this.state.data[0] value is really available or not. You can try this-
render() {
return (
<div className="products-container">
{this.state.data && this.state.data.length > 0 && <ProductItem data={this.state.data[0]} />}
</div>
);
}

Understanding React.JS JSON feed and how to parse

I've got the following code which is looping through an JSON file from an API and loops through some posts.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//https://alligator.io/react/axios-react/
import axios from 'axios';
export default class PostList extends React.Component {
state = {
posts: []
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const posts = res.data;
this.setState({ posts });
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Pulls in post slugs from Domain
</p>
<ul>
{ this.state.posts.map(post => <li>{post.name} - {post.username} </li>)}
</ul>
</div>
)
}
}
This works fine, and gets the information which was needed.
Now, in my test JSON file, the format is as follows:
https://jsonplaceholder.typicode.com/users
But in my actual JSON file from WordPress Rest API, we have another item, named core_layout:
JSON image
My issue is, trying to use the same code such as {post.name}does not get the information needed such as core_layout->image->name.
Is there an easy way around this?
Thanks all!
EDIT:
Tried the answers below, but still no luck, get the error TypeError: Cannot read property 'map' of undefined:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//https://alligator.io/react/axios-react/
import axios from 'axios';
export default class PostList extends React.Component {
state = {
posts: [],
coreLayout: {}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
// const posts = res.data;
//this.setState({ posts });
const { posts, core_layout: coreLayout } = res.data;
this.setState({ posts, coreLayout });
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Pulls in post slugs from domain
</p>
<ul>
{ this.state.posts.map(post => <li>{post.name} - {post.core_layout.image.name}</li>)}
</ul>
</div>
)
}
}
EDIT 2:
Tried the below: This gets the title, but again, not the actual corelayout I need.
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
let dataURL = "http://zinsseruk.com/wp-json/wp/v2/posts?per_page=1";
fetch(dataURL)
.then(res => res.json())
.then(res => {
this.setState({
movies: res
})
})
}
render() {
let movies = this.state.movies.map((movie, index) => {
return <div key={index}>
<p><strong>Title:</strong> {movie.title.rendered}</p>
<p><strong>Title:</strong> {movie.core_layout.acf_fc_layout}</p>
</div>
});
return (
<div>
<h2>Star Wars Movies</h2>
{movies}
</div>
)
}
}
export default App;
Replace const posts = res.data; with const posts = res.data.core_layout;. Then you'll get an array similar to what you have in your test file.
I think you need to understand the JSON structure you receive from the API. Where is located core_layout property? Inside each post property as a children?
So in the posts loop you can use post.core_layout.image.name for image name, for example (and so on with other properties).
If core_property is at the root of the data you receive, you can load it inside your state like so:
state = {
posts: [],
coreLayout: {}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
// This is equivalent of doing
// const posts = res.data.posts
// const coreLayout = res.data.core_layout
const { posts, core_layout: coreLayout } = res.data;
this.setState({ posts, coreLayout });
})
}
Then use it in your code by using local component state:
render() {
...
// For example image name:
console.log('image name', this.state.coreLayout.image.name)
...
}

Accessing certain item after fetching data from API with react

I am learning react and stumbled on something that seems like an absolute beginner problem. Anyway I am fetching data from an API and would like to know how to get a certain element from the JSON. I have tried different variations with [] but with no success.
JSON:
[{"name":"gfhf","id":1,"organizer":"hfgh"},{"name":"World Cup","id":2,"organizer":"FIFA"}]
React code:
import React, { Component } from "react";
import Tournaments from "./Tournaments";
const tournyAPI = 'http://localhost:8080/api/tournaments';
class template extends Component {
constructor() {
super();
this.state = {
data: [],
}
}
componentDidMount() {
fetch(tournyAPI)
.then((Response) => Response.json())
.then((findresponse) => {
console.log(findresponse)
this.setState({
data:findresponse,
})
})
}
render() {
return (
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="jumbotron text-center">
{
this.state.data.map((dynamicData, key) =>
<div>
<h1>{dynamicData.name}</h1>
</div>
)
}
</div>
</div>
</div>
</div>
);
}
}
export default template;
My goal would be to display only World cup for example.
You can filter out whatever you want from the response from the API. Like below:
Notice the line findresponse.filter(res => res.name === "World Cup");
componentDidMount() {
fetch(tournyAPI)
.then((Response) => Response.json())
.then((findresponse) => {
console.log(findresponse)
findresponse.filter(res => res.name === "World Cup");
this.setState({
data:findresponse,
})
})
}

How to use React SetState on nested data with empty top level names?

I have the following JSON data:
[
{"ID":1,"Latitude":"-41.276253","Longitude":"173.283842","Image":"Church.jpg"},
{"ID":2,"Latitude":"-41.267783","Longitude":"173.279114","Image":"Centre.jpg"}
]
I am trying to import it so it can be rendered & started with the following code:
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
console.log(data);
this.setState({
latitude: data.Latitude,
longitude: data.Longitude,
image: data.Image
});
});
}
This doesn't as the data is multidimensional/nested. But every example I've found is using better structured data with top level names.
How can I use setState & render to display this data?
If you want to import json from a js file you would do it like this.
Data.js
const Data = [
{"ID":1,"Latitude":"-41.276253","Longitude":"173.283842","Image":"Church.jpg"},
{"ID":2,"Latitude":"-41.267783","Longitude":"173.279114","Image":"Centre.jpg"}
]
export default Data
Then import it where you want to use it. Now you can map through the data as you like.
App.js
import Data from './data'
import React, {Component} from 'react'
class App extends Component {
state = { Data:[] }
componentDidMount() { this.setState({ Data: Data }) }
render() {
return(
<div> {this.state.Data.map(item => <div> The id is: {item.ID} </div> }</div>
)
}
}
Maybe you want to change the names of the items, and return a new data structure with less attributes this is how you would do it.
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
const newData = data.map(item => {
latitude:item.Latitude,
longitude: item.Longitude,
image: item.Image}
}
this.setState({
Data:newData
});
});
}
Now if you want to display this data in render.
renderData = () => {
return (
<div>
{this.state.Data.map(item => (
<div>
{item.latitude}
{item.longitude}
<img src={item.img} />
</div>
)}
</div>
)
}
render() {
return (
<div> {this.renderData()} </div>
)
}
It would probably just be easier to first construct what you want, then do a mapping in the rendering. It looks like you don't even need to do anything to convert it, since the json data is exactly what you want in the first place. So:
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
console.log(data);
this.setState({ data });
});
}
render() {
return (
<div>
{this.state.data.map(datum => (element))}
</div>
);
}

React: Auto update date and view with new information called from json API

I am calling data from coinmarketcap.com API and can not find a way to make the code auto update. I would like to get this code to update the information every 30 seconds or so.
If I call something the wrong thing... or this is a basic question, sorry this is my first week with React.
Here is what I have and it works great at loading the information from coinmarketcap.com on the when the app first loads.
Main Component (file: Crypto.jsx)
import React, { Component } from 'react';
import CryptoItem from './parts/CryptoItem';
class Crypto extends Component{
render(){
return(
<div id="CryptoItems">
<div id="data">
<CryptoItem cryptocoin="bitcoin" />
<CryptoItem cryptocoin="ethereum" />
<CryptoItem cryptocoin="ripple" />
<CryptoItem cryptocoin="iconomi" />
<CryptoItem cryptocoin="litecoin" />
<CryptoItem cryptocoin="bitcoin-cash" />
</div>
</div>
);
}
}
export default Crypto;
Child Component (file: /parts/CryptoItem.jsx)
import React, { Component } from 'react';
const urlForUsername = cryptocoin => `https://api.coinmarketcap.com/v1/ticker/${cryptocoin}/`
class CryptoItem extends Component {
constructor(props){
super(props)
this.state = {
requestFailed: false
}
}
componentDidMount(){
fetch(urlForUsername(this.props.cryptocoin))
.then(response =>{
if(!response.ok){
throw Error("Network request failed")
}
return response
})
.then(d => d.json())
.then(d => {
this.setState({
cryptoData: d[0]
})
},() => {
this.setState({
requestFailed: true
})
})
}
render() {
if(this.state.requestFailed) return <p>Failed...</p>
if(!this.state.cryptoData) return <p>Loading...</p>
return(
<ul className="CryptoItem" data-sort={ `${this.state.cryptoData.percent_change_24h}` } id={ `${this.state.cryptoData.symbol}PriceChangeID` }>
<li>
{this.state.cryptoData.name}:
</li>
<li>
$ <span id={ `${this.state.cryptoData.symbol}Price` }>{this.state.cryptoData.price_usd}</span>
</li>
<li className="PreCentChange">
<span id={ `${this.state.cryptoData.symbol}PriceChange` }>{this.state.cryptoData.percent_change_24h}</span><b>%</b>
</li>
</ul>
);
}
}
export default CryptoItem;
First, extract out the logic in componentDidMount method in child component to a separate method as below.
fetchResult = () => {
fetch(urlForUsername(this.props.cryptocoin))
.then(response =>{
if(!response.ok){
throw Error("Network request failed")
}
return response
})
.then(d => d.json())
.then(d => {
this.setState({
cryptoData: d[0]
})
},() => {
this.setState({
requestFailed: true
})
})
}
After that modify the componentDidMount method as below.
componentDidMount(){
this.fetchResult()
setInterval(this.fetchResult, 30000)
}
Note that, setInterval method can be used to execute a logic periodically. The first argument is the function which contains the logic that needs to be executed periodically. Second argument is the time interval in milliseconds.