I am trying to obtain and display data in a React app from the samhsa.org API. I am able to console.log an XML string though I cannot seem get the node values. I have exhausted the last week trying to figure this out. Forgive me, I am learning React and not experienced with XML.
When I run:
import React from 'react';
import axios from 'axios';
import PropTypes from 'prop-types';
import { parser, parseString } from 'xml2js';
function ResourcesGrid(props) {
return (
<div>
<ul className='resources-list'>
{props.resources.map((resource) => {
return (
<li key={resource.title} className='resource-item'>
<ul className='space-list-items'>
<li>{resource.description}</li>
</ul>
</li>
)
})}
</ul>
</div>
)
}
ResourcesGrid.propTypes = {
resources: PropTypes.array.isRequired
}
export default class Resources extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
componentDidMount () {
let xml = 'http://content.samhsa.gov/ext/api/items?q-taxo=PanicDisorders~Recovery';
return axios.get(xml)
.then(function (res) {
console.log(res.data);
return res.data;
});
this.setState = {
resources: resources
}
}
render() {
return (
<div>
{!this.state.resources
? <p>LOADING...</p>
: <ResourcesGrid resources={this.state.resources} />
}`enter code here`
</div>
)
}
}
I get an object an object that contains a XML string:
When I log res.data I get a string.
I can't figure out how to get to the next level (EX: res.data["description"]).
I have tried 'xml2js':
componentDidMount () {
let xml = 'http://content.samhsa.gov/ext/api/items?q-taxo=PanicDisorders~Recovery';
return axios.get(xml)
.then(function (res) {
parser.parseString(res, function(err,result){
resData = result['data'];
console.log(resData);
});
return resData;
});
this.setState = {
resources: resources
}
}
and get TypeError: Cannot read property 'parseString' of undefined:
I've tried to convert it to JSON as well.
Am I way off? I need help!
Related
Okay, so here is my problem. I am getting props via getserversideprops, and I have tried multiple fixes but I can not get it to display. Here is the code:
import React, { Component } from 'react';
import rpstyle from '/styles/home/recentPosts.module.css'
export default class RecentPosts extends Component {
constructor() {
super()
this.state = { posts: this.props.posts }
}
static async getServerSideProps() {
const res = await fetch('http://localhost:5000/search/recentposts')
const json = await res.json()
return { posts : json }
}
viewAllButton(){
if(this.props.viewAll != false){
return (
<div className={rpstyle.viewAll}>
<a href='#'>View All Posts</a>
</div>
)
} else {
return null
}
}
render() {
return (
<div className={rpstyle.container}>
<hr />
<h1>Recent Posts</h1>
{console.log(this.props.posts)}
{this.viewAllButton()}
</div>
)
}
}
For some reason I can not find a good guide for class-based components and this method. If someone has any ideas on making this not display undefined please let me know!
hi you can use the same api for classes as well, if you are using a recent version of next you need to change the return object of getServerSideProps, it needs to have a props key
import React, { Component } from 'react';
export default class RecentPosts extends Component {
constructor(props) {
super(props)
this.state = { posts: props.data }
}
viewAllButton(){
if(this.props.viewAll != false){
return (
<div className={rpstyle.viewAll}>
<a href='#'>View All Posts</a>
</div>
)
} else {
return null
}
}
render() {
return (
<>
<hr />
<h1>Recent Posts</h1>
{console.log(this.state)}
{/* {this.viewAllButton()} */}
</>
)
}
}
export async function getServerSideProps() {
const res = await fetch('https://reqres.in/api/users')
const json = await res.json()
return { props : json }
}
Okay, I took a little bit from your answers as well some more research and found this to work great:
import Recentstuff from '../components/home/recentposts/RecentPosts'
export default function Home({data}) {
return (
<div>
<Recentstuff posts={data} />
</div>
)
}
export const getServerSideProps = async () => {
const res = await fetch('http://localhost:5000/search/recentposts')
const data = await res.json()
return { props : {data} }
}
I hope this helps anyone who had the same issue. You have to call it within the page file, the pass it as a prop. MAKE SURE you properly destructure it, because I had a good little time tracking down why my api calls were showing on my api but not within my client.
I am using an API which contains cards. And to call this API, I am using Axios.
So far so good, but I want to return the deck_id and for some reason it does not work. And I get the error "this.state.card.map is not a function"
Here is my current code:
import React from "react";
import axios from "axios";
const CARD_API = "https://deckofcardsapi.com/api/deck/new/shuffle/";
export default class PersonList extends React.Component {
constructor(props) {
super(props)
this.state = {
card: []
}
}
async componentDidMount() {
const card= await axios.get(CARD_API)
this.setState({ card})
}
render() {
return (
<ul>
{this.state.card.map(card=>
<li>{card.deck_id}</li>
)}
</ul>
)
}
}
In axios you will get data inside response.data , so this is how you will get access to data
try {
const response = await axios.get(MOVIE_API); //<-- This will have a lot more thing apart from data you need
const movie = response.data; //<---- SOLUTION
this.setState({ movie })
} catch (err) {
console.log(err)
}
Note : Always put your async await code within try catch block if
possible
I am getting the following error in my code. Can you please help me to understand the issue. I have included my page component and task list component.
TypeError: this.state.tasks.map is not a function
Page Show.js
import React, { Component } from 'react';
import axios from 'axios';
import TasksList from './TasksList';
export default class Show extends Component {
constructor(props) {
super(props);
this.state = {tasks: [] };
}
componentDidMount(){
axios.post('http://mohamed-bouhlel.com/p5/todolist/todophp/show.php')
.then(response => {
this.setState({ tasks: response.data });
})
.catch(function (error) {
console.log(error);
})
}
tasksList(){
return this.state.tasks.map(function(object,i){
return <TasksList obj = {object} key={i} />;
});
}
render() {
return (
<div>
{ this.tasksList() }
</div>
)
}
}
Page TasksList.js
import React, { Component } from 'react';
export default class TasksList extends Component {
render() {
return (
<div>
<div>{this.props.obj.task}</div>
</div>
)
}
}
Using a GET request and correct protocol (https vs http) seems to resolve the issue.
axios.get("https://mohamed-bouhlel.com/p5/todolist/todophp/show.php")
Response.data is not an array and basically you can't call map on a non-array.
I suggest console.log(response.data) to check the data type.
And I guess maybe you're doing a axios.post instead of a correct axios.get. log the response.data and you'll find out.
I am getting this error after trying to map over API response. Appreciate your help. I am able to see response in console but is not rendering. I have managed to resolve typerror thanks to this: ReactJs - TypeError: Cannot read property 'map' of undefined but struggling to move forward.
Thank you.
Code below:
import React from 'react';
import './App.css';
import prettyFormat from 'pretty-format';
import axios from 'axios';
class App extends React.Component {
state = {
rates: []
}
onSubmitExchange = this.onSubmitExchange.bind(this);
onSubmitExchange() {
axios({
"method":"GET",
"url":"https://coingecko.p.rapidapi.com/exchange_rates",
"headers":{
"content-type":"application/octet-stream",
"x-rapidapi-host":"coingecko.p.rapidapi.com",
"x-rapidapi-key":"f4756b8409msh762478a357cd070p10685fjsnce9080fa5478"
}
})
.then((response)=>{
//console.log(response)
//response is an object with a data property that contains the rates
const { rates } = response.data;
this.setState({ rates })
})
}
render() {
let xrpName = (this.state.rates.xrp && this.state.rates.xrp) ? this.state.rates.xrp.name : undefined
console.log(xrpName)
console.log(this.state.rates)
const items = this.state.rates.map((item) => {return <li>{ item.name }</li> });
return (
<div>
<ul>
{ items }
</ul>
<button onClick={this.onSubmitExchange}>FIRE</button>
</div>
)
}
}
export default App;
The API returns an object. You can't map over it like an array. First change
state = {
rates: []
}
to
state = {
rates: {}
}
Then use Object.keys(rates) to map over it.
Sorted with this. Needed to use Object.keys() and then map over it as Ola mentioned.
const cryptoTable = Object.entries(cryptos).map((crypto, index) => {
return (<tr>
<td key={index}>{crypto[1].name}</td>
<td>{crypto[1].unit}</td>
<td>{crypto[1].value}</td>
<td className="tag">{crypto[1].type}</td>
</tr>)
})
return (
<div>
<div>
{ cryptoTable }
</div>
<button onClick={this.onSubmitExchange}>FIRE</button>
<button onClick={this.onFilterHandler}>Filter</button>
</div>
)
}
}
export default App;
I have set up an API with Rails, with a http://localhost:3001/api/words endpoint exposing the following data:
[{"id":1,"term":"Reach","definition":"Reach is the number of people who had any content from your Page or about your Page enter their screen.","example":"","author":"Loomly","credit":"https://www.loomly.com/","created_at":"2018-11-02T03:21:20.718Z","updated_at":"2018-11-02T03:21:20.718Z"},{"id":2,"term":"Emoji","definition":"A small digital image or icon used to express an idea, emotion, etc., in electronic communication","example":"","author":"Loomly","credit":"https://www.loomly.com/","created_at":"2018-11-02T03:23:50.595Z","updated_at":"2018-11-02T03:23:50.595Z"}]
I am now trying to simply display this data (ideally as an unordered list) in a React.js frontend application built with Create React App, and here is the content of my App.js file:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor () {
super()
this.state = {}
this.getWords = this.getWords.bind(this)
this.getWord = this.getWord.bind(this)
}
componentDidMount () {
this.getWords()
}
fetch (endpoint) {
return window.fetch(endpoint)
.then(response => response.json())
.catch(error => console.log(error))
}
getWords () {
this.fetch('/api/words')
.then(words => {
if (words.length) {
this.setState({words: words})
this.getWord(words[0].id)
} else {
this.setState({words: []})
}
})
}
getWord (id) {
this.fetch(`/api/words/${id}`)
.then(word => this.setState({word: word}))
}
render () {
let {words, word} = this.state
return (
<div>
{Object.keys(words).map((key) => {
return (
<div key={word.id}>
<p>{word.term}</p>;
</div>
)
})}
</div>
)
}
}
export default App;
I believe the problem is located in the following area of the code:
render () {
let {words, word} = this.state
return (
<div>
{Object.keys(words).map((key) => {
return (
<div key={word.id}>
<p>{word.term}</p>;
</div>
)
})}
</div>
)
}
I have tried to follow the steps explained in this tutorial, as well as in that other tutorial, while keeping the layout of the page as simple as possible (no bells & whistles from semantic-ui-css), and no matter what I try, I keep getting into of the following errors:
TypeError: Cannot convert undefined or null to object
Unexpected token, expected “,”
Failed to compile: 'word' is not defined no-undef
The solution explained in this article led me to the code I have now, but there is something I am missing about the way to structure my React app: can you point me in the right direction?
getWords () {
fetch('http://localhost:3001/api/words')
.then((response) => {
return response.json();
})
.then((res) => {
// console.log(res); you should get the response you mentioned
this.setState({words: res});
});
}
Then check Are you getting data in your state by consoling it.
Then you can work on it using following
render{
return(
<div>
{ this.state.words.map((val) => (
<span>{val.term}</span>
))}
</div>
)
}
The problem is here: let {words, word} = this.state;
this.state doesnt have word property yet. You could initialize this.state like this:
this.state = {
words: [],
word: {}
};
be free to ask
There are two issues with the code in the question:
words & word are not defined.
Iteration through words in the render() function was not set properly with keys.
Thanks to the answers and comments left on this question, here is the code I ended up using:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor () {
super()
this.state = {
words : [],
word : {}
}
this.getWords = this.getWords.bind(this)
this.getWord = this.getWord.bind(this)
}
componentDidMount () {
this.getWords()
}
fetch (endpoint) {
return window.fetch(endpoint)
.then(response => response.json())
.catch(error => console.log(error))
}
getWords () {
this.fetch('/api/words')
.then(words => {
if (words.length) {
this.setState({words: words})
this.getWord(words[0].id)
} else {
this.setState({words: []})
}
})
}
getWord (id) {
this.fetch(`/api/words/${id}`)
.then(word => this.setState({word: word}))
}
render () {
let {words} = this.state
return (
<ul className="words-container">
{Object.keys(words).map((key) => {
return (
<li className="word-container" key={key}>
{words[key].term}: {words[key].definition}.
</li>
)
})}
</ul>
)
}
}
export default App;