Passing props in react - fetching - json

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

Related

Cannot read property 'map' of undefined in React + Phoenix framework

I'm new to React. I have provided Postgresql API and I want to add those data in Material UI Table.
I've made some mistakes and I'm unable to figure to out.
I'm using API calls for the first time using Axios. So please guide me to solve this issue.
I'm using React.js for frontend work, Phoenix framework for backend, and PostgreSQL database.
The below component is used to handle API request using Axios
import axios from "axios"
import MedicineCard from './MedicineCard'
class Medicines extends React.Component {
constructor() {
super();
this.state = { medicines: [] };
}
componentWillMount() {
axios.get('http://localhost:4000/medicines')
.then(response => {
this.setState({ medicines: response.data.medicines });
})
.catch(error => {
console.log(error);
});
}
render() {
const posts = this.state.medicines.map((medicine, index) =>
<MedicineCard
key = { index }
medid = {medicine.medid}
medname = {medicine.medname}
/>
)
return (
<div>
{posts}
</div>
)
}
}
export default Medicines
Below Component is used for Material UI Table
import React from 'react'
import MaterialTable from 'material-table'
class MedicineCard extends React.Component{
render(){
const data=[
{medid:this.props.medid,medname:this.props.medname}
]
const column=[
{
title:'Medicine_ID',field:'medid'
},
{
title:'Medicine_Name',field:'medname'
}
]
return (
<div>
<MaterialTable title="Material Table"
data={data}
column ={column}
/>
</div>
);
}
}
export default MedicineCard
This component is used to display UI
import React from 'react'
import Medicines from './Medicines'
const Test = () => (
<div>
<Medicines />
</div>
)
export default Test
Please help me and guide me out to solve this issue

Child component does not render properly

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

How to create dynamic routes with react-router-dom?

I learn react and know, how to create static routes, but can't figure out with dynamic ones. Maybe someone can explain, I'll be very grateful. Let there be two components, one for rendering routes, and another as a template of a route. Maybe something wrong in the code, but hope You understand..
Here is the component to render routes:
import React, { Component } from 'react';
import axios from 'axios';
import Hero from './Hero';
class Heroes extends Component {
constructor(props) {
super(props);
this.state = {
heroes: [],
loading: true,
error: false,
};
}
componentDidMount() {
axios.get('http://localhost:5555/heroes')
.then(res => {
const heroes = res.data;
this.setState({ heroes, loading: false });
})
.catch(err => { // log request error and prevent access to undefined state
this.setState({ loading: false, error: true });
console.error(err);
})
}
render() {
if (this.state.loading) {
return (
<div>
<p> Loading... </p>
</div>
)
}
if (this.state.error || !this.state.heroes) {
return (
<div>
<p> An error occured </p>
</div>
)
}
return (
<div>
<BrowserRouter>
//what should be here?
</BrowserRouter>
</div>
);
}
}
export default Heroes;
The requested JSON looks like this:
const heroes = [
{
"id": 0,
"name": "John Smith",
"speciality": "Wizard"
},
{
"id": 1,
"name": "Crag Hack",
"speciality": "Viking"
},
{
"id": 2,
"name": "Silvio",
"speciality": "Warrior"
}
];
The route component (maybe there should be props, but how to do it in the right way):
import React, { Component } from 'react';
class Hero extends Component {
render() {
return (
<div>
//what should be here?
</div>
);
}
}
export default Hero;
I need something like this in browser, and every route url should be differentiaie by it's id (heroes/1, heroes/2 ...):
John Smith
Crag Hack
Silvio
Each of them:
John Smith.
Wizard.
and so on...
Many thanks for any help!)
Use Link to dynamically generate a list of routes.
Use : to indicate url params, :id in the case
Use the match object passed as props to the rendered route component to access the url params. this.props.match.params.id
<BrowserRouter>
/* Links */
{heroes.map(hero => (<Link to={'heroes/' + hero.id} />)}
/* Component */
<Route path="heroes/:id" component={Hero} />
</BrowserRouter>
class Hero extends Component {
render() {
return (
<div>
{this.props.match.params.id}
</div>
);
}
}
Update so this works for React Router v6:
React Router v6 brought some changes to the general syntax:
Before: <Route path="heroes/:id" component={Hero} />
Now: <Route path="heroes/:id" element={<Hero />} />
You can't access params like with this.props.match anymore:
Before: this.props.match.params.id
Now: import {useParams} from "react-router-dom";
const {id} = useParams();
You can now just use id as any other variable.
To do this you simply add a colon before the url part that should be dynamic. Example:
<BrowserRouter>
{/* Dynamic Component */}
<Route path="heroes/:id" component={Hero} />
</BrowserRouter>
Also you can use the useParams hook from react-router-dom to get the dynamic value for use in the page created dynamically. Example:
import { useParams } from "react-router-dom";
const Hero = () => {
const params = useParams();
// params.id => dynamic value defined as id in route
// e.g '/heroes/1234' -> params.id equals 1234
return (...)
}

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

Parser data with format json in react

I am new to react.js and I am trying to display data in JSON format in a table. So what I did is:
import React from 'react';
import axios from 'axios';
class TableUser extends React.Component {
constructor(props) {
super(props);
this.state = {
libelle_produit: ''
};
}
componentDidMount(){
axios
.get('admin/prdtId/')
.then(({ data })=> {
this.setState({
libelle_produit: data.libelle_produit
});
})
.catch((err)=> {})
}
render() {
return <div>
<p>{ this.state.libelle_produit }</p>
</div>;
}
}
export default TableUser;
i'd want to be able to access the libelle product of each component and print those on the website
[{"libelle_produit":"test produit"}]
Thanks
<div>
{ this.state.libelle_produit != '' ? this.state.libelle_produit.map( (item, index) =>
<p>{libelle_produit</p>
}
</div>
If the array isnt empty, then loop trough the array and return a p tag with the title of the libelle_produit