how to fetch array of objects from json - 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>
);
}
}

Related

Not able to fetch data from server in my ReactJs site

Getting undefined data type error while fetching data from JSON
I have searched at many places but didn't get the suitable answer
import SavedData from "./SavedData";
export default class Saved extends React.Component {
constructor() {
super();
this.state = {
loading: true,
datas: [],
};
}
async componentDidMount() {
const url = "https://todo-list-site.herokuapp.com/todo-data";
const response = await fetch(url);
const todoData = response.json().then((res) => {
this.setState({ datas: res });
});
}
render() {
console.log(this.state.datas[0].description); //not able to get data
return (
<div>
{/* {this.state.datas.map((items) => (
<SavedData
key={items.countTodo}
title={items.title}
desc={items.desc}
/>
))} */}
</div>
);
}
}
Someone help me so that I can proceed
Just like Dave Newton has pointed out in the comments, the render is triggered before the request completes. This is normal and you just need to handle it properly.
If you see the console logs of this codesandbox, you can see that initially this.state.datas is just an empty array [] - so any attempt to access this.state.datas[0].description will be undefined. Only after the state is updated when the request completes, the logs show the data retrieved - this is because according to the mount lifecycle of a React Component, the render() is called before the componentDidMount() and also the request being async.
This is very common and it is even recommended by the official React docs to make HTTP calls in componentDidMount(). The docs also has provided an example to handle this issue.
import SavedData from "./SavedData";
export default class Saved extends React.Component {
constructor() {
super();
this.state = {
loading: true, // we initially set this to true
datas: [],
};
}
async componentDidMount() {
const url = "https://todo-list-site.herokuapp.com/todo-data";
const response = await fetch(url);
const todoData = response.json().then((res) => {
this.setState({
datas: res,
loading: false // when the request is complete, we set this to false
});
});
}
render() {
if (this.state.loading) {
// during the first render, loading will be true and we
// can return a loading message or a spinner
return (
<div>Loading...</div>
);
}
// when render is called after the state update, loading will be false
// and this.state.datas will have the fetched data
console.log(this.state.datas[0].description);
return (
<div>
{this.state.datas.map((items) => (
<SavedData
key={items.countTodo}
title={items.title}
desc={items.desc}
/>
))}
</div>
);
}
}
Your datas state is initially an empty array until your componentDidMount fires and sets the state. As a result, your console log will then be undefined until the state is set. In order to combat this you must wait for this.state.datas[0] to be true before accessing the first objects description within the array. The following code seems to work as expected
import React from "react";
export default class Saved extends React.Component {
constructor() {
super();
this.state = {
loading: true,
datas: []
};
}
async componentDidMount() {
const url = "https://todo-list-site.herokuapp.com/todo-data";
const response = await fetch(url);
response.json().then((res) => {
this.setState({ datas: res });
});
}
render() {
console.log(this.state.datas[0] && this.state.datas[0].description);
return (
<div>
{this.state.datas.map((items, i) => (
<div key={i}>
<div> title={items.title}</div>
<div> desc={items.description}</div>
</div>
))}
</div>
);
}
}

Trouble getting into json data object

I have some code that allows the user to click a image to then update the page and display the clicked on champions name. the json data looks like this -http://ddragon.leagueoflegends.com/cdn/10.16.1/data/en_US/champion/Alistar.json
I console.log response.data and see a object of objects and am wondering how to get passed the section that has the response.data.(whatever champion the user picked). I have tried adding a variable like response.data.champion but I assume no variables can be passed like that seeing how it doesnt work.
Not sure if its even worth posting the code but just in case! My code is below, the fetch im trying to go through is in NewChamp function.
To make my request simpler, All i want to know for example is how i would get response.data.(whatever the user clicked).key from any possible champion clicked like http://ddragon.leagueoflegends.com/cdn/10.16.1/data/en_US/champion/Alistar.json or http://ddragon.leagueoflegends.com/cdn/10.16.1/data/en_US/champion/Anivia.json
or whatever other champion the user clicks.
import React, { Component } from 'react';
import './Champions.css';
class AllChamps extends Component {
render() {
let champion = this.props.champion;
return(
<div className='champions'>
<h1> all champions</h1>
{Object.keys(this.props.champions).map((s) => (
<div className='champs' onClick={() => this.props.NewChamp({s, champion})}>
<img
alt='Champion Images'
src={`http://ddragon.leagueoflegends.com/cdn/10.16.1/img/champion/${s}.png`}
onClick={this.props.onClick}
></img>
{s}
</div>
))}
</div>
)}}
class SpecificChamp extends Component {
render() {
let champion = this.props.champion
let Spec = champion[champion.length - 1];
return (
<div className='champions'>
<h1> 1 champions</h1>
<div className='champs'>
<button onClick={this.props.onClick}></button>
{Spec}
</div>
</div>
)}
}
class Champions extends Component {
constructor(props) {
super(props);
this.handleAllChamps = this.handleAllChamps.bind(this);
this.handleSpecificChamp = this.handleSpecificChamp.bind(this);
this.NewChamp = this.NewChamp.bind(this);
this.state = {
champions: [],
champion: [],
clickedChamp: false,
thisChamp: 'ahri'
}}
NewChamp = (props) =>
{
let s = props.s;
props.champion.push(s);
fetch(`http://ddragon.leagueoflegends.com/cdn/10.16.1/data/en_US/champion/${s}.json`)
.then(response => { return response.json() })
.then((response) => {
Object.keys(response.data).map((a) => (s = a
))})
fetch(`http://ddragon.leagueoflegends.com/cdn/10.16.1/data/en_US/champion/${s}.json`)
.then(response => { return response.json() })
.then((response) => {
console.log(s)
console.log(response.data)
console.log(props.champion)
})
console.log(`http://ddragon.leagueoflegends.com/cdn/10.16.1/data/en_US/champion/${s}.json`);
}
handleAllChamps = (props) => {
this.setState({ clickedChamp: true,
})};
handleSpecificChamp = () => {
this.setState({ clickedChamp: false,
})};
componentDidMount(props) {
const apiUrl = `http://ddragon.leagueoflegends.com/cdn/10.16.1/data/en_US/champion.json`;
fetch(apiUrl)
.then(response => { return response.json() })
.then((response) => {
this.setState({
champions: response.data
}, () => (this.state.champions))
return
})
}
render() {
const clickedChamp = this.state.clickedChamp;
let display;
if (clickedChamp ) {
display = <SpecificChamp champion={this.state.champion} onClick={this.handleSpecificChamp} s={this.state.thisChamp}/>;
} else {
display = <AllChamps champions={this.state.champions} onClick={this.handleAllChamps} NewChamp={this.NewChamp} thisChamp={this.state.thisChamp} champion={this.state.champion} />;
}
return (
<div>
<div className='champions'></div>
{display}
</div>
);
}
}
export default Champions;
Your response is in the form of Object of Objects. You've to use JSON.stringify(response.data) in order to view the entire data as a string in the debug console.
You will have to destructure the Object of objects.
Object.keys(response.data).map((key)=> console.log(response.data[key]))
In this case if it is just one key
response.data[s]

Reactjs fetch method returns empty array

I am trying to fetch some data, which is in the form:
[
{
"id": 1,
"some_data": "..."
},
...
]
What I am trying to get is a list displaying the items from the fetch. If I put the same data in a file within the project, it works.
However when I tried to map it, I got an error saying "this.data.map is not a function". So I changed it a bit by using Array.from(). It currently looks like this:
export default class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
items = [];
};
this.getData = this.getData.bind(this);
}
getData = () => {
fetch("URL",{
method: "get",
header: { "Content-Type": "application/json" }
})
.then(response => {
var array = Array.from(response.json())
this.setState({items: array});
})
}
render() {
const list = this.state.items.map((r, i) => {
return (
<Item
id = { r[i].id }
some_data = { r[i].some_data }
...
/>
)
})
return(
<div>
<Item
p = {list}
>
</div>
)
}
}
First of all no state is neede to store the response. Its happening due to the state value is not reflecting in your render.
Call a function inside success response & map the response inside the function & set State there.
OR
Put the below code outside render function assigning to variable like below
const list = this.state.items.map((r, i) => {
return (
)
})
return(
)
}
render () {
{list}
}
Try something like this.....
It's better to load the data once component is mounted. Also, there's no URL, I'm assuming that you've hidden this.
Once you 'see' what's in response, you can code against that accordingly.
export default class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
items = [];
};
// this.getData = this.getData.bind(this);
}
componentDidMount(){
// Attempt to load data once component mounted.
this.getData();
}
getData = () => {
// Don't you need the URL below, or have you deliberately hidden it?
fetch("URL",{
method: "get",
header: { "Content-Type": "application/json" }
})
.then(response => {
console.log(response); // See exactly what is in response....
var array = Array.from(response.json())
console.log(array); // Check array is really what you want
// You could try a JSON.Parse....
var jsonArray = JSON.Parse(response);
console.log(jsonArray);
this.setState({items: array});
})
}
render() {
const list = this.state.items.map((r, i) => {
return (
<Item
id = { r[i].id }
some_data = { r[i].some_data }
...
/>
)
})
return(
<div>
<Item
p = {list}
>
</div>
)
}
}

How to store a value of prop in a variable and then access it in react?

I am using cdn for react
Actually I have two JSON FILE,
abc.json
[
{
"apiKey":"642176ece1e7445e99244cec26f4de1f"
}
]
reactjs.json
[
{
"642176ece1e7445e99244cec26f4de1f": {
"src": "image_1.jpg",
"id" : "1"
}
}
]
I actually want that first of all I get apiKey from the first json file and after with the help of it i like to get the value of src
1) How can I do this in React using axios?
2) Is that Possible that we can directly get the src from reactjs.json ? If yes then How?
What I tried, but it gives error..
class FetchDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [],
api:[]
};
//this.listImages = this.listImages.bind(this);
}
componentDidMount() {
axios.get('abc.json').then(res => {
console.log(res);
this.setState({ api: res.data });
});
axios.get('reactjs.json').then(res => {
console.log(res);
this.setState({ images: res.data });
});
}
render() {
return (
<div>
{this.state.api.map((api, index) => (
<Pictures key={index} apikeys={api.apiKey} />
))}
</div>
);
}
}
class Pictures extends React.Component {
render() {
return (
<h1>
alt={this.props.apikeys}
</h1>
{this.state.images.map((images, index) => (
<h1 key={index}> apikeys={images.+`{this.props.apikeys}`+.src} </h1>
//Error at this point
))}
);
}
}
ReactDOM.render(
<FetchDemo/>,
document.getElementById("root")
);
Using axios you are making a request. This means that your JSON would be served from a end point. If you really need to require the json file in this fashion try importing
import abc from './abc.json';
componentDidMount = () => {
this.setState({
json: abc
})
}

Can't access JSON object information React/Redux

Feels like I'm missing something obvious here - but I can't figure out how to access my JSON data. I have a Container component:
class About extends Component {
componentDidMount(){
const APP_URL = 'http://localhost/wordpress/'
const PAGES_URL = `${APP_URL}/wp-json/wp/v2/pages`
this.props.fetchAllPages(PAGES_URL, 'about')
}
render(){
return (
<div>
<Header/>
<div className="bg">
<div className="home-wrapper">
<h1>AAAAABBBBBOOOOUUUUUT</h1>
<Counter/>
<AboutInfo />
</div>
</div>
<Footer/>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({ fetchAllPages }, dispatch)
}
export default connect(null, mapDispatchToProps)(About);
And a Smart component:
class AboutInfo extends Component {
render(){
console.log(this.props.page);
console.log(this.props.page.id);
return (
<div>
<h1>This is ID: {this.props.page.id}</h1>
</div>
)
}
}
const mapStateToProps = ({ page }) => {
return { page }
}
export default connect(mapStateToProps)(AboutInfo);
My action:
export const fetchAllPages = (URL, SLUG) => {
var URLEN;
if(!SLUG){
URLEN = URL
} else {
URLEN = URL + "?slug=" + SLUG
}
return (dispatch) => {
dispatch(fetchRequest());
return fetchPosts(URLEN).then(([response, json]) => {
if(response.status === 200){
if(!SLUG) {
dispatch(fetchPagesSuccess(json))
} else {
dispatch(fetchPageBySlugSuccess(json))
}
} else {
dispatch(fetchError())
}
})
}
}
const fetchPageBySlugSuccess = (payload) => {
return {
type: types.FETCH_PAGE_BY_SLUG,
payload
}
}
My reducer:
const page = (state = {}, action) => {
switch (action.type) {
case FETCH_PAGE_BY_SLUG:
console.log(action.paylod)
return action.payload
default:
return state
}
}
This gives me:
When I console.log(this.props.page) in my AboutInfo component, it prints the object, but when I print console.log(this.props.page.id) it gives me undefined. Why can't I print the JSON content? Thanks!
page is an array and hence this.props.page.id is undefined. You might want to access the first element in array in which case you would do
this.props.page[0].id
but you might also need to add a test, since before the response is available you will be trying to access page[0].id and it might break.
You could instead write
this.props.page && this.props.page[0] && this.props.page[0].id
Getting data from the store is async So you must adding loading varibale on your reducer
class AboutInfo extends Component {
render(){
if(this.props.loading) return (<div>loading</div>);
return (
<div>
<h1>This is ID: {this.props.page.id}</h1>
</div>
);
}
}
const mapStateToProps = ({ page, loading }) => {
return { page, loading }
}
on your action try returing
json.page[0]
That is because page is an array and the id is a property of its 1st element.
So use this.props.page[0].id
If the logged object in your screenshot is the this.props.page then you will need and additional .page as that is also a part of the object this.props.page.page[0].id