Accessing JSON object within Object using React/Axios - json

I’m working with an API that shows data for cryptocurrencies called CryptoCompare. I’m a React noob but I’ve managed to use Axios to do the AJAX request. However I’m having trouble accessing the JSON elements I want.
Here’s what the JSON looks like: https://min-api.cryptocompare.com/data/all/coinlist
Here is my request:
import React, { Component } from 'react';
import './App.css';
import axios from "axios";
var NumberFormat = require('react-number-format');
class App extends Component {
constructor(props) {
super(props);
this.state = {
coinList: []
};
}
componentDidMount() {
axios.get(`https://min-api.cryptocompare.com/data/all/coinlist`)
.then(res => {
const coins = res.data;
//console.log(coins);
this.setState({ coinList: coins});
});
}
// Object.keys is used to map through the data. Can't map through the data without this because the data is not an array. Map can only be used on arrays.
render() {
console.log(this.state.coinList.Data);
return (
<div className="App">
{Object.keys(this.state.coinList).map((key) => (
<div className="container">
<span className="left">{key}</span>
<span className="right"><NumberFormat value={this.state.coinList[key].CoinName} displayType={'text'} decimalPrecision={2} thousandSeparator={true} prefix={'$'} /></span>
</div>
))}
</div>
);
}
}
export default App;
I am able to output some JSON using console.log(this.state.coinList.Data);. It outputs the JSON object, but I am unable to console.log properties of the object itself.
How would I, for example, output the CoinName property of the first element 42?
console.log(this.state.coinList.Data.CoinName) doesn’t work
nor does console.log(this.state.coinList.Data[0].CoinName) etc…

You are iterating over this.state.coinList while you want to iterate over this.state.coinList.Data.
Try this:
render() {
const data = this.state.coinList.Data;
if (data == null) return null;
return (
<div className="App">
{Object.keys(data).map((key) => (
<div className="container">
<span className="left">{key}</span>
<span className="right"><NumberFormat value={data[key].CoinName} displayType={'text'} decimalPrecision={2} thousandSeparator={true} prefix={'$'} /></span>
</div>
))}
</div>
);
}
CodeSandbox here: https://codesandbox.io/s/3rvy94myl1

I also stumbled with that same problem as yours. You cannot access an object inside a data because it is empty when the render happens. What I did was I made a conditional render where if the data is empty, it will just show a loading screen or something like that. And when the data loads , it will access the object inside that data. I can now access the object inside because I waited for the data to load inside render.
I hope this answer can help future react users
return (
<div>
{this.state.coinList.length>0? <h1>{this.state.coinList[0].coinName}</h1>: "Loading"}
</div>
);
}
Added: To console.log the data , you can create a new component inside the conditional render. Inside that component, you can access all the data you want because it is rendered after the data is loaded.

You're might have to parse the JSON. Might be good to do that before you save it.
const coins = JSON.parse(res.data)

Related

How to use fetch() in react front-end to get data from express back-end?

I'm trying to make a full-stack web-app using react and express. It's going pretty well atm but here's my problem:
So I have express running in back-end. All paths are used by react router except for '/api'. At the '/api/blogposts' path my server.js send the results of a query I made to the mySQL server. (I've checked it and this part works. If I browse to /api/blogposts my browser shows a json with the contents of my blogposts table).
My problem is with getting it to show in my react front-end. I'm trying to use fetch() but it doesn't work. Here's my code for the component that is supposed to fetch the blogposts:
import React from 'react';
import './Blogposts.css';
import SingleBpost from '../SingleBpost/SingleBpost.js';
class Blogposts extends React.Component {
constructor(props) {
super(props);
this.state = {
receivedPosts: []
};
}
async getBpostsFromServer() {
const response = await fetch("/api/blogposts");
let myPosts = await response.json();
this.setState({receivedPosts: myPosts});
}
componentDidMount() {
this.getBpostsFromServer();
}
render() {
console.log(this.state.receivedPosts);
return(
<div id="Blogposts">
<SingleBpost title="OwO" date="18/12/2021" author="Kepos Team" body="Hello, this is a test for the blogposts!" />
</div>
);
}
}
export default Blogposts;
Just to clarify the {this.state.generateBlogpost()} in the render method is just to check if I can get the data for now. Once this works I will feed it into another component's props like this:
<SingleBpost title={this.state.generateBlogpost().title} date={this.state.generateBlogpost().date} author={this.state.generateBlogpost().author} body={this.state.generateBlogpost().body} />
Anyways: does anyone know why this doesn't work? I've tried a few things but I just can't get it to work. What am I doing wrong?
Thanks in advance for any help!
You need to set the state of the variable receivedPosts in the fetch function like this :
this.setState({receivedPosts: results});
Also, you can call the function generateBlogpost() at the load of the Component Blogposts by adding the following function :
componentDidMount() {
this.generateBlogpost();
}
this one is useless
.then((results) => {
this.state.receivedPosts = results;
});
return this.state.receivedPosts;
}
//instead you should use setState({receivedPosts: data.data})

Trying to fetch data from API in React - TypeError: recipes.map is not a function

Im trying to fetch Data from an API and pass it into my component as props. The Problem is I get this type error. Some googling showed, that the API seems to return an object and the map() function is expecting an Array. Okay, console logged what I get from the API and it is indeed an object. Easy fix right? However, none of the fixes I found for this work. This is my original code with the error:
export async function getStaticProps(context) {
const res = await fetch("https://rezepte-api-test.babafresh.de/recipes.json")
const data = await res.json()
return {
props: { recipes: data }, // will be passed to the page component as props
}
export default function Test(recipes) {
console.log(typeof recipes);
return (
<div>
<ul>
{recipes.map((recipe) =>(
<div key={recipe.name}>
<li>{recipe.name}</li>
</div>
))}
</ul>
</div>
);
I Did try some of the following fixes I found here, but none of my recipes from the array get rendered. Im in front of a white page, is my map function wrong here?
export default function Test(recipes) {
let arr = Object.entries(recipes);
return (
<div>
<ul>
{arr.map((recipe) =>(
<div key={recipe.name}>
<li>{recipe.name}</li>
</div>
))}
</ul>
</div>
);
Id appreciate any pointers.
From your first snippet, not sure this return statement at the top-level execution context is correct or what you intended to do.
return {
props: { recipes: data }, // will be passed to the page component as props
}
And call to the receipes api returns an array not an object
So what you are doing with Object.entries is incorrect. Simple, use the arrayed props with the map function in JSX.
For the shortest fix,
let arr = receipes.receipes;
P.S. If you think this set of API data is only meant for this component and will not be shared, try using the useEffect hook to fetch the data inside this component itself and render.
export default function Test() {
const [receipes, setReceipes] = useState('');
useEffect(() => setReceipes(await fetch("https://rezepte-api-test.babafresh.de/recipes.json").then(res => res.json())), []);
return (
<div>
<ul>
{receipes.map((recipe) =>(
<div key={recipe.name}>
<li>{recipe.name}</li>
</div>
))}
</ul>
</div>
);
}
The API is returning an array of objects only.
To access the data from the API, you can just map over it as it an array
<div>
<ul>
{res.data.map((recipe) =>(
<div key={recipe.name}>
<li>{recipe.name}</li>
</div>
))}
</ul>
</div>
Are you using useEffect? Usually these problems are related to async fetching and initially getting undefined or empty lists etc. as a prop before data is actually available. If you are using effect, then try to catch the first error by calling map only if recipes is defined.
For your second solution: check the contents of arr by logging it.

Fetch data from JSON local file in React

I would need some help to fetch some data in a local file calling data.json to my React component. The data is very simple, but when i tried to connect with my component, all I have in the component appear less than the information I added from the data file.
this is my data.json:
{ "data": [
{ "id": "1",
"name": "john"
},
]}
...and this is my component where i need to fetch the data and where everything is working less than the information I want to connect and appear completely blank.
This is the function where i past the information in the first instant to send the information to the state.
function RenderFoo({data, name}) {
return (
<div>{data.name}</div>
)}
export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
data : [data]
}}
render() {
const dataExample = this.state.data.map((element) => {
return (
<div key={element.url}>
<RenderFoo data ={ element }/>
</div>
)})
return (
<div>
<Card >
{dataExample}
</Card>
</div>)
The screen appear blank in the part of the component that I connect the data but without any error in the other part of the component where everything is working. I think the sintaxis to get the information is not right any reason don't read the data.
And if I change data.name in the function is giving error. I don't know if I'm missing the key or so.
Moving all the data to the main component is worthy neither because I will need to increase the data after and I will thousands of lines, and create a complete back end would be pointless for this kind of application
Thanks
Your state has a property data which is an array. Each element of that array is an object with properties id and name -- and maybe url?
So then what are the props supposed to be here:
function RenderFoo({data, name}) {
return (
<div>{data.name}</div>
)}
Does RenderFoo take a single property data which is the the whole data object? Or does it take the properties of data as individual props? Either is fine, but it feels like you are mixing the two. So remove name from the props.
<div key={element.url}>
Do all elements in your data have a url property? I'm only asking because your sample just shows name and id.
this.state = {
data : [data]
}}
This also looks suspect to me. You are taking the variable data and making it a single element in an array. I'm not sure exactly what your data variable looks like, but I think you probably want to set it as the entire state, this.state = data.
Try this:
import React, { Component } from "react";
import json from "./data";
function RenderFoo({ data }) {
return <div>{data.name}</div>;
}
export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
data: json.data
};
}
render() {
return (
<div>
{this.state.data.map((element) => (
<div key={element.id}>
<RenderFoo data={element} />
</div>
))}
</div>
);
}
}
I removed the <Card> component because I don't know where you imported it from, but you can easily add it back it.

React Unable to Access Json Resposne from API

In my website on login,i get a confirmation and a token which i need to store and pass as a property throughout all the pages.I am able to receive the token,but i am unable to store the value for the token and store it as a state value.
Here is the code i have tried so far.
import React from 'react'
import ReactDOM from 'react-dom'
import {Login_Submit_style,Login_button_style,Login_text_field_style,
password_style,para_login_style} from './style'
import Supers from 'superagent'
class Login extends React.Component
{
constructor(props)
{
super(props);
this.state={username:'',password:''}
this.Login_data_password=this.Login_data_password.bind(this)
this.Login_data_username=this.Login_data_username.bind(this)
this.MainRedirect=this.MainRedirect.bind(this)
this.api_call_login=this.api_call_login.bind(this)
}
Login_data_username(e)
{
this.setState({username:e.target.value})
}
Login_data_password(password)
{
this.setState({password:password.target.value})
}
MainRedirect()
{
window.location = '/main';
}
api_call_login()
{
Supers.post('http://127.0.0.1:8000/user_ops/user_login/')
.send({'username':this.state.username,'password':this.state.password})
.then(response => response.json())
.then(responseData=>{
console.log(responseData);
})
}
render()
{
return(
<div style={{background:'yellow'}}>
<div>
<h1 style={{marginLeft:550}}>Login Page</h1>
<div>
<p style={para_login_style}><b>Username</b></p>
<input type="text" style={Login_text_field_style} onChange={this.Login_data_username}/>
<h2>{this.state.username}</h2>
</div>
<div>
<p style={para_login_style} ><b>Password</b></p>
<input type="password" style={password_style} onChange={this.Login_data_password}/>
</div>
<div>
<button style = {Login_Submit_style} onClick={this.api_call_login}> Log in </button>
</div>
</div>
</div>
)
}
}
This is the Format in which i get the response:
{"Successful_Login": "True", "token": "d278f30445aa0c37f274389551b4faafee50c1f2"}
So ideally i would like to store the values for both the keys returned from the json output.Adn when i use response.body,i am able to get the data in the above format.
I don't know if this will be helpful to you, but I'll try.
Things like XHR calls from a browser to an API are done asynchronously. What you get back is a promise that will execute a function you give it when the call to the API is completed. Your code rightly has a callback function.
However, I don't think that callback function can call setState, because I think (I might be wrong) React wouldn't like it.
I use Redux for React as a way of storing stuff that the rest of the app can just grab when it needs it. Better still, Redux is integrated into React in such a way that whenever this central database is updated, any component that pulls in a piece of data from it (via props) gets updated (re-rendered) automatically.
I think I should point you to the documentation for Redux for more information. There are alternatives to Redux, too.
Good luck, and ask more questions if you get stuck.
In order to set a new state with the values from a json response, I ideally call this.setState right in your promise response.
api_call_login()
{
Supers.post('http://127.0.0.1:8000/user_ops/user_login/')
.send({'username':this.state.username,'password':this.state.password})
.then(response => response.json())
.then(responseData=>{
this.setState({
Successful_Login: responseData.Successful_Login,
token: responseData.token
})
}
state will be updated when response arrives.
If possible try to use lowercase or camelCase to your keys.
It would be great if you could post link where we can see what exactly is going on, but the way I understand this you would have to add .set('Accept', 'application/json') in your request to get correct json. So, your code should be like:
Supers.post('http://127.0.0.1:8000/user_ops/user_login/')
.send({'username':this.state.username,'password':this.state.password})
.set('Accept', 'application/json')
.then(response => response.json())
.then(responseData=>{
console.log(responseData);
})
Since I cannot test, you would have to look if it works. Alternatively, I would suggest you to try using superagent
Let me know if it helps!

Accessing state in React render method after API request

I'm working on my first complicated React app and I am making a request to a movie API. My site allows the user to do a search in a searchbar for whatever movie, show, actor, etc... that they are searching for. I'm pulling the user's search query and inserting it into an api request like this:
export const getDetails = (id) => {
return new Promise(function(resolve, reject) {
axios.get(`https://api.themoviedb.org/3/movie/` + id +`?api_key=&language=en-US`)
.then(function(response) {
resolve(response)
})
.catch(function(error) {
reject(error)
})
})
}
I'm able to get the data like this and console.log it:
import React, { Component } from 'react';
import Header from '../header';
import {Link} from 'react-router-dom';
import axios from 'axios';
import Footer from '../Footer.js';
import Searchbar from '../header/searchbar.js';
import List from '../results/list';
import {getDetails} from '../api/getDetails';
class Detail extends Component {
constructor(props) {
super(props);
this.state = {
id: this.props.match.params.id,
result: null,
error: false,
}
}
componentWillMount() {
getDetails(this.state.id).then(function(response){
this.setState({result: response});
console.log(response.data.original_title);
console.log(response.data.homepage);
console.log(response.data.popularity);
console.log(response.data.release_data);
console.log(response.data.overview);
}.bind(this)).catch(function(err) {
this.setState({
result:"There was a problem loading the results. Please try again.",
error: true
})
}.bind(this))
}
render() {
return(
<div>
<Header/>
<div className="details-container">
<h2>Details: </h2>
</div>
</div>
)
}
}
export default Detail
Console.logging it in the componentWillMount function successfully logs the data but I am not able to access the data in the render function via something like {response.data.orginal_title). How would I render the data being logged in componentWillMount?
TLDR; You can access your state variables from within your render function via this.state. Something like: console.log(this.state.result.data.origin_title) outside of the jsx and {this.state.response.data.orginal_title} inside the jsx.
P.S. You are using the correct this.
The following are picky recommendations and explanations, feel free to disregard.
It's recommended to make requests for data in componentDidMount. That can be read here in the docs for componentDidMount.
You're using arrow functions already in your get details function, if you convert the rest of your functions to arrow functions you no longer have to explicitly bind this to each one; it's automatically set be the this of it's parent. See the "No Separate This" section in the MDN docs
If you don't need any of the header information I would save response.data into your state so you don't have to type as much when you want to access the data. this.state.result.original_title vs this.state.result.data.original_title. That's just me and I'm lazy.
axios does return a promise like Eric said so you don't actually need to wrap it in the extra promise. You can just straight up return it and since arrow functions automatically return one line expressions you can spiff that up into a one liner:
export const getDetails = id => axios.get(`https://api.themoviedb.org/3/movie/${id}?api_key=&language=en-US`)
Finally you should be able to access the data you've stored in your state from your render function as mentioned in #3 above. Outside of the JSX you can console.log it like normal console.log(this.state.result), inside your JSX, however, you will need to make sure you escape with {} like: <div>{this.result.original_title}</div>
Small working example here: https://codesandbox.io/s/zqz6vpmrw3
You can simply use
{this.state.result}
inside the render.