Understanding React.JS JSON feed and how to parse - json

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

Related

Extract slug from unsplash

I have a list of photos, fetched from this url https://picsum.photos/v2/list.
In this list there is slug that should be extracted, for example https://unsplash.com/photos/_h7aBovKia4.
Here is fetch thing I used
import React, {Component} from 'react';
import '../App.css';
import ImageList from "./ImageList";
class App extends Component {
constructor() {
super();
this.state = {
images: []
};
}
componentDidMount() {
fetch("https://picsum.photos/v2/list")
.then(res => res.json())
.then(data => {
this.setState({ images: data });
})
.catch(err => {
console.log('Error happened during fetching!', err);
});
}
render() {
return (
<div className="container">
<h2 className="title">Images list</h2>
<ImageList data={this.state.images}/>
</div>
)
}
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
And here is ImageList Component
import React from "react";
import Image from "./Image";
const ImageList = props => {
const results = props.data;
let images = results.map(image => <Image url={image.url} key={image.id}/>);
return (
<ul className="img-list">{images}</ul>
);
};
export default ImageList;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
How can I get that slug from each photo url? without it, images aren't showing in browser, just their alts
UPD. Image Component
import React from "react";
const Image = props => {
return (
<li className="image-wrap">
<img src={props.url} alt="Something went wrong"/>
</li>
)
}
export default Image;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
You have to use download_url property, not url.
The url points to a Unsplash page with comments, site interface etc. The download_url however is a direct link to the image.

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

how to fetch array of objects from json

This is the api http://skunkworks.ignitesol.com:8000/books/ ,
I am trying to fetch the array results from it using the fetch method but instead get an error cannot fetch value of undefined
import React, { Component } from 'react';
class App extends Component {
constructor() {
super()
this.state = {
books: []
}
}
componentDidMount() {
fetch('http://skunkworks.ignitesol.com:8000/books/')
.then(res => res.json())
.then(data => this.setState({ books: data }))
.catch(e => {
console.log(e);
return e;
});
}
render() {
let book = []
book = this.state.books.results;
console.log(book[0])
return (
<div>
<h1>Books</h1>
</div>
)
}
}
export default App;
this is my code.
Also I have observed that json data are usually like [{}] but here it is {} format.
please suggest me some solution.....
As I see from your url link, you json array of data is present in the results key of the returned object from the API.
So if you're only interested by the results you should do something like that :
import React, { Component } from 'react';
class App extends Component {
state = {
books: []
}
async componentDidMount() {
const objectFromUrl = await fetch('http://skunkworks.ignitesol.com:8000/books/')
const data = await objectFromUrl.json() //first way
// or you can use destructuring way
const { results } = await objectFromUrl.json() //second way
this.setState({
books: data.results // results key contains your '[{}]' data an array of objects
})
}
render() {
const { books } = this.state
return (
<div>
<h1>Books</h1>
{books.map(book => (
<h2> {book.id} </h2>
)}
</div>
);
}
// You can use destructuring again to get only key you're interested by
render() {
const { books } = this.state
return (
<div>
<h1>Books</h1>
{books.map(({id, formats}) => (
<h2> {id} </h2>
<h2> { formats[ˋapplication/pdf’] } </h2>
)}
</div>
);
}
}

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

Display API data using Axios and a list in React

I'm attempting to make a request to this https://www.themoviedb.org/documentation/api API in a React project and then display JSON data on my site.
I'm using Axios to make the request and I have been able to make the request and get the appropriate JSON data and console.log it or view it in the React tools in Firefox. However, I am having difficulty displaying the data in a ul. Initially I had an error pertaining to having a unique key for each list item, and I have since resolved that (or so I believe).
Here's my request and how I am attempting to render the data:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from "axios";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
posts: []
}
}
componentDidMount() {
axios.get(`https://api.themoviedb.org/3/movie/now_playing?api_key=*apikeyhere*&language=en-US&page=1`)
.then(res => {
const posts = res.data.results.map(obj => [obj.title, obj.overview]);
this.setState({ posts });
});
}
/* render() {
return (
<div>
<h1>Movie API data</h1>
<ul>
{this.state.posts.map(post =>
<li key={post.toString()}>{post.title}</li>
)}
</ul>
</div>
);
}
}
*/
render() {
return (
<ul>
{this.state.posts.map(function(post, index){
return (
<div key={index}>
<h1>{post.title}</h1>
<p>{post.overview}</p>
</div>
)
}
)}
</ul>
);
}
}
As you can see I attempted multile approaches to rendering this. What's wrong with my code and why isn't the JSON data rendering in the ul on my site?
I think, you have an error inside success fuction ({title: obj.title, overview: obj.overview})
componentDidMount() {
axios.get(`https://api.themoviedb.org/3/movie/now_playing?api_key=*apikeyhere*&language=en-US&page=1`)
.then(res => {
const posts = res.data.results.map(obj => ({title: obj.title, overview: obj.overview}));
this.setState({ posts });
});
}