I'm new to react and trying to fetch some data through an API. I got response on console but i'm unable to get any result on the page. This is my Index page:
const url = "https://chicken-coop.p.rapidapi.com/games/"
class PcComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
games: [],
}
}
GameSearch(term) {
const req = unirest("GET", "https://cors-anywhere.herokuapp.com/" + url + term);
req.query({
"platform": "pc",
"s": term
});
req.headers({
"x-rapidapi-host": "API Name"
"x-rapidapi-key": "API Key",
"useQueryString": true
});
req.end((res) => {
if (res.error) throw new Error(res.error);
const games = res.body.Search;
this.setState({ games: games}, () =>{ console.log(this.state)});
console.log(res.body);
});
}
render() {
const GameSearch = _.debounce((term) => {this.GameSearch(term)},300)
return (
<div>
<Search onSearchTermChange = {GameSearch} />
{
this.state.games && this.state.games.map((game) => {
return <Game {...game}/>
})
}
</div>
)
}
}
And My Code to Display the received data
class Game extends Component {
render() {
const {title, description, image} = this.props;
return (
<div className="game">
<div className="title-description">
<h1 className="title">{title}</h1>
<h2 className="description">{description}</h2>
</div>
<div className="image">
<img src={image} alt="My Game Poster" />
</div>
</div>
)
}
}
I noticed that initially the state is '[]' as i defined but after the setState it gets undefined.
I attached the response i'm getting from the API. Please help me fix this :D
Related
I am writing a UI page to display a list of new messages, but I have gone wrong gin my code somewhere and not all of my page renders. I can't seem to find where.
My arrays correctly capture the data as I have tested this in console.log.
The text that should render on the page from the "displayNewMessage" doesn't work. Everything else renders.
Can anyone see where I have gone wrong please?
class Welcome extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
messageData: [],
newMessages: [],
isLoading: false
};
}
componentDidMount() {
this.setState({ isLoading: true });
this.setState({ userID: this.props.location.state });
const serachByUserId = this.props.location.state;
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url =
"my-url" +
serachByColleagueId;
fetch(proxyurl + url)
.then((res) => res.json())
.then((data) => this.setState({ data: data }))
.then(
fetch(
proxyurl +
"my-URL"
)
.then((res) => res.json())
.then((messageData) =>
this.setState(
{ messageData: messageData, isLoading: false },
() => {}
)
)
);
}
render() {
const { data, isLoading, messageData } = this.state;
if (isLoading) {
return (
<div className="pageLoading">
<p>Loading...</p>
</div>
);
}
return (
<div>
<div>
<p>
<strong>
Welcome {data.Forename} {data.Surname}
</strong>
</p>
</div>
<div className="InfoBox">
<p>
<strong>Message Backlog</strong>
</p>
<p className="helpText">
The below Orders have open chats awaiting a response. Click on
the order number to send and view messages.
</p>
</div>
{this.getMessages(messageData)}
</div>
);
}
getMessages(messageData) {
var newMessagesArray = [];
var latestMessageIndex;
var latestMessage;
messageData.message_Subjects.forEach(saveNewMessage);
function saveNewMessage(sub) {
console.log(sub);
latestMessageIndex = sub.message_Chain.length - 1;
latestMessage = sub.message_Chain[latestMessageIndex];
if (latestMessage.sentFromId.toString().length === 7) {
var message_Chain = {
dateTime: latestMessage.dateTime,
sentFromId: latestMessage.sentFromId,
messagebody: latestMessage.messageBody,
messageChainId: latestMessage.messageChainId,
};
var message_subject = {
userId: sub.userId,
subjectId: sub.messageSubjectId,
subject: sub.subject,
message_Chain: message_Chain,
};
newMessagesArray.push({ message_Subject: message_subject });
} else {
// do nothing
}
}
if (newMessagesArray.length > 0) {
return ( <div>{newMessagesArray.forEach(displayNewMessage)}</div>)
} else {
return <p>No New messages.</p>;
}
function displayNewMessage(arrayItem) {
console.log(arrayItem);
return (
<div>
<ul>
<li>Subject = {arrayItem.message_Subject.subject}</li>
<li>Order number = {arrayItem.message_Subject.orderNumber}</li>
<li>Date and Time = {arrayItem.message_Subject.dateTime}</li>
<li>
message = {arrayItem.message_Subject.message_Chain.messageBody}
</li>
<li>
sent by = {arrayItem.message_Subject.message_Chain.sentFromId}
</li>
</ul>
</div>
);
}
}
}
export default Welcome;
Found away around this not rendering on the page with no need for the displayNewMessage function.
if (newMessagesArray.length > 0) {
return (
newMessagesArray = newMessagesArray.map((item) =>
<li key={item.id}>Subject = {item.message_Subject.subject}</li>
<li> etc..... </li>
))
} else {
return <p>No New messages.</p>;
};
i want to display data based on its id. i have 2 page, app.js and display.js. in app.js i already display a table and clickable data to link to display.js. but i cant display data n display.js based on its id. i use API to get this all data and data in display.js is looping all data on result json and not only by id that i click on app.js.
can anyone helpme to pass the id from app.js to display.js and not loop data on display.js?
here's my code
App.js
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
errors: null,
isLoading: true
};
}
getData = async () => {
const option = {
url:api/url
method: 'POST',
headers: {
"Access-Control-Allow-Origin": "*"
},
data: {
"data": {
"data": "111111"
},
"encrypt": 0
}
};
axios(option)
.then(response => {
const tableData = response.data.data.map(post => {
const {id, name, type} = post;
return [
<Link to={'/display'}>{id}</Link>, //when i click this it link to display.js and in display.js only display data based on this id
<Link to={'/display'}>{name}</Link>,
<Link to={'/display'}>{type}</Link>
];
});
this.setState({
data: tableData,
isLoading: false
});
})
);
}
componentDidMount() {
this.getData();
}
render() {
const columns = ["ID", "Name", "Type"];
const options = {
filterType: "dropdown",
responsive: "scroll",
selectableRows:false
};
return (
<div>
<center><h3>Table</h3></center><br/>
{!isLoading ? (
<MUIDataTable
data={this.state.data}
columns={columns}
options={options}
/>)
: (
<p>Loading...</p>
)}
</div>
);
}
}
export default App
display.js
class App extends React.Component {
// State will apply to the posts object which is set to loading by default
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true,
errors: null
};
}
// Now we're going to make a request for data using axios
getData = async () => {
const option = {
url:api/url
method: 'POST',
headers: {
"Access-Control-Allow-Origin": "*"
},
data: {
"data": {
"data": "111111"
},
"encrypt": 0
}
};
axios(option)
.then(response => {
this.setState({
data: response.data.data,
isLoading: false,
});
console.log(response.data);
const data = JSON.parse(data);
})
);
}
componentDidMount() {
this.getData();
}
// Putting that data to use
render() {
const { isLoading, data} = this.state;
return (
<React.Fragment>
<h3>Data display</h3><br/>
<div>
{!isLoading ? (
data.map(post => {
const {id, name, age, type, gender} = post;
return (
//from API this data is looping and more than 1, i want to after click id from app.js it will link to this display.js page and only show data based on id
<div>
<Card>
<CardHeader color="info">
<h4 >Data </h4>
</CardHeader>
<CardBody>
<div><b>ID</b></div>
<div>{id}</div>
<div><b>Name</b>
<div>{name}</div>
<div><b>age</b></div>
<div>{age}</div>
<div><b>type</b></div>
<div >{type}</div>
<div><b>gender</b></div>
<div>{gender}</div>
</CardBody>
</Card>
<br/>
</div>
);
})
) : (
<p>Loading...</p>
)}
</div>
</React.Fragment>
);
}
}
export default App;
anyone can help to only show page display.js based on id i click in app.js?
You can pass the id within of the clicked row within the link child
<Link to={{
pathname: '/display',
state: {
data: post
}
}}></Link>
and in your display component you can get the id to send with the request
const { data } = this.props.location.data
and in your display component you'll get all the clicked row data and you can remove the loop from the render as well as the request
Using Parse, I am querying the database and getting an imageURL back. React is not updating the dom.
componentWillMount and just regular curly brackets.
export const profileImage = async objectId => {
const query = new Parse.Query(Parse.User);
query.equalTo("objectId", objectId);
const image = await query.find();
console.log(typeof image[0].attributes.image);
console.log(image[0].attributes.image);
return image[0].attributes.image; // return image;
}; // Query for a specific user and get image!
I imported it currently and it does the console logs so the function is executing but never rendering.
export default class MyDashboard extends Component {
constructor(props) {
super(props);
this.state = {
profilePic: "",
};
}
componentDidMount() {
this.setState({ profilePic: profileImage(window.localStorage.objectId) });
}
render() {
return (
<div>
<Sidebar />
<div className={style.Componentcontainer} />
<div className={style.main}>
</div>
<div className={style.profile}>
<div> {this.state.profilePic} </div>
}
I eventually plan to put the string into an image tag, I just got to get this rendering first.
Your function is asynchronous, so setState will not wait and will render undefined.
To fix this, you should return a promise, and consume it with a .then() and set the state there instead. You should also use window.localStorage.getItem(), rather than trying to access a property immediately.
export const profileImage = objectId => {
const query = new Parse.Query(Parse.User);
query.equalTo("objectId", objectId);
return query.find();
};
export default class MyDashboard extends Component {
constructor(props) {
super(props);
this.state = {
profilePic: ""
};
}
componentDidMount() {
profileImage(window.localStorage.getItem(objectId)).then(image => {
this.setState({ profilePic: image[0].attributes.image });
});
}
render() {
return (
<div>
<Sidebar />
<div className={style.Componentcontainer} />
<div className={style.main} />
<div className={style.profile}>
<img src={this.state.profilePic} />
</div>
</div>
);
}
}
I am starting to learn React and creating my second project at the moment. I am trying to usi MovieDb API to create a movie search app. Everything is fine when I get the initial list of movies. But onClick on each of the list items I want to show the details of each movie. I have created a few apps like this using vanilla JS and traditional XHR call. This time I am using fetch API which seems straightforward ans simply to use, however when I map through response data to get id of each movie in order to retrieve details separately for each of them I get the full list of details for all the items, which is not the desired effect. I put the list of objects into an array, because after setState in map I was only getting the details for the last element. I know that I am probably doing something wrong within the API call but it might as well be my whole REACT code. I would appreciate any help.
My code
App.js
import React, { Component } from 'react';
import SearchInput from './Components/SearchInput'
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state =
{
value: '',
showComponent: false,
results: [],
images: {},
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleOnChange = this.handleOnChange.bind(this);
this.getImages = this.getImages.bind(this);
this.getData = this.getData.bind(this);
}
ComponentWillMount() {
this.getImages();
this.getData();
}
getImages(d) {
let request = 'https://api.themoviedb.org/3/configuration?api_key=70790634913a5fad270423eb23e97259'
fetch(request)
.then((response) => {
return response.json();
}).then((data) => {
this.setState({
images: data.images
});
});
}
getData() {
let request = new Request('https://api.themoviedb.org/3/search/movie?api_key=70790634913a5fad270423eb23e97259&query='+this.state.value+'');
fetch(request)
.then((response) => {
return response.json();
}).then((data) => {
this.setState({
results: data.results
});
});
}
handleOnChange(e) {
this.setState({value: e.target.value})
}
handleSubmit(e) {
e.preventDefault();
this.getImages();
this.setState({showComponent: true});
this.getData();
}
render() {
return (
<SearchInput handleSubmit={this.handleSubmit} handleOnChange={this.handleOnChange} results={this.state.results} images={this.state.images} value={this.state.value} showComponent={this.state.showComponent}/>
);
}
}
export default App;
SearchInput.js
import React, {Component} from 'react';
import MoviesList from './MoviesList';
class SearchInput extends Component {
render() {
return(
<div className='container'>
<form id='search-form' onSubmit={this.props.handleSubmit}>
<input value={this.props.value} onChange={this.props.handleOnChange} type='text' placeholder='Search movies, tv shows...' name='search-field' id='search-field' />
<button type='submit'>Search</button>
</form>
<ul>
{this.props.showComponent ?
<MoviesList value={this.props.value} results={this.props.results} images={this.props.images}/> : null
}
</ul>
</div>
)
}
}
export default SearchInput;
This is the component where I try to fetch details data
MovieList.js
import React, { Component } from 'react';
import MovieDetails from './MovieDetails';
let details = [];
class MoviesList extends Component {
constructor(props) {
super(props);
this.state = {
showComponent: false,
details: []
}
this.showDetails = this.showDetails.bind(this);
this.getDetails = this.getDetails.bind(this);
}
componentDidMount() {
this.getDetails();
}
getDetails() {
let request = new Request('https://api.themoviedb.org/3/search/movie?api_key=70790634913a5fad270423eb23e97259&query='+this.props.value+'');
fetch(request)
.then((response) => {
return response.json();
}).then((data) => {
data.results.forEach((result, i) => {
let url = 'https://api.themoviedb.org/3/movie/'+ result.id +'?api_key=70790634913a5fad270423eb23e97259&append_to_response=videos,images';
return fetch(url)
.then((response) => {
return response.json();
}).then((data) => {
details.push(data)
this.setState({details: details});
});
});
console.log(details);
});
}
showDetails(id) {
this.setState({showComponent: true}, () => {
console.log(this.state.details)
});
console.log(this.props.results)
}
render() {
let results;
let images = this.props.images;
results = this.props.results.map((result, index) => {
return(
<li ref={result.id} id={result.id} key={result.id} onClick={this.showDetails}>
{result.title}{result.id}
<img src={images.base_url +`${images.poster_sizes?images.poster_sizes[0]: 'err'}` + result.backdrop_path} alt=''/>
</li>
)
});
return (
<div>
{results}
<div>
{this.state.showComponent ? <MovieDetails details={this.state.details} results={this.props.results}/> : null}
</div>
</div>
)
}
}
export default MoviesList;
MovieDetails.js
import React, { Component } from 'react';
class MovieDetails extends Component {
render() {
let details;
details = this.props.details.map((detail,index) => {
if (this.props.results[index].id === detail.id) {
return(
<div key={detail.id}>
{this.props.results[index].id} {detail.id}
</div>
)} else {
console.log('err')
}
});
return(
<ul>
{details}
</ul>
)
}
}
export default MovieDetails;
Theres a lot going on here...
//Here you would attach an onclick listener and would fire your "get details about this specific movie function" sending through either, the id, or full result if you wish.
//Then you getDetails, would need to take an argument, (the id) which you could use to fetch one movie.
getDetails(id){
fetch(id)
displayresults, profit
}
results = this.props.results.map((result, index) => {
return(
<li onClick={() => this.getDetails(result.id) ref={result.id} id={result.id} key={result.id} onClick={this.showDetails}>
{result.title}{result.id}
<img src={images.base_url +`${images.poster_sizes?images.poster_sizes[0]: 'err'}` + result.backdrop_path} alt=''/>
</li>
)
});
Thanks for all the answers but I have actually maanged to sort it out with a bit of help from a friend. In my MovieList I returned a new Component called Movie for each component and there I make a call to API fro movie details using each of the movie details from my map function in MovieList component
Movielist
import React, { Component } from 'react';
import Movie from './Movie';
class MoviesList extends Component {
render() {
let results;
if(this.props.results) {
results = this.props.results.map((result, index) => {
return(
<Movie key={result.id} result={result} images={this.props.images}/>
)
});
}
return (
<div>
{results}
</div>
)
}
}
export default MoviesList;
Movie.js
import React, { Component } from 'react';
import MovieDetails from './MovieDetails';
class Movie extends Component {
constructor(props) {
super(props);
this.state = {
showComponent: false,
details: []
}
this.showDetails = this.showDetails.bind(this);
this.getDetails = this.getDetails.bind(this);
}
componentDidMount() {
this.getDetails();
}
getDetails() {
let request = new Request('https://api.themoviedb.org/3/search/movie?api_key=70790634913a5fad270423eb23e97259&query='+this.props.value+'');
fetch(request)
.then((response) => {
return response.json();
}).then((data) => {
let url = 'https://api.themoviedb.org/3/movie/'+ this.props.result.id +'?api_key=70790634913a5fad270423eb23e97259&append_to_response=videos,images';
return fetch(url)
}).then((response) => {
return response.json();
}).then((data) => {
this.setState({details: data});
});
}
showDetails(id) {
this.setState({showComponent: true}, () => {
console.log(this.state.details)
});
}
render() {
return(
<li ref={this.props.result.id} id={this.props.result.id} key={this.props.result.id} onClick={this.showDetails}>
{this.props.result.title}
<img src={this.props.images.base_url +`${this.props.images.poster_sizes?this.props.images.poster_sizes[0]: 'err'}` + this.props.result.backdrop_path} alt=''/>
{this.state.showComponent ? <MovieDetails details={this.state.details}/> : null}
</li>
)
}
}
export default Movie;
I'm new to react and trying to pass a global function to components to avoid repeating it in each of them. That doesn't work, I get an undefined error when I try to call it in the components.
Here is my code :
import React from 'react';
//components
import League from './League';
class App extends React.Component {
state = {
leagues: {},
};
componentDidMount() {
this.getLeagues();
}
get(url) {
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append("X-Mashape-Key", "mysecretkeyblablabla");
var myInit =
{
headers: myHeaders
};
return fetch(url,myInit)
.then(function(response) {
if(response.ok) {
return response.json().then(function(json) {
return json.data;
});
}
});
};
getLeagues() {
this.get('https://sportsop-soccer-sports-open-data-v1.p.mashape.com/v1/leagues').then((data) => {
this.setState({leagues: data.leagues});
});
}
render() {
const leagues = Object
.keys(this.state.leagues)
.map(key => <League get={this.get} key={key} details={this.state.leagues[key]} />
);
return(
<div className="App">
<div className="App-header">
<h1>Welcome to Foot Stats app (made in ReactJS)</h1>
</div>
<p className="App-intro">
Here is the place where I should put the countries.
</p>
<ul>
{leagues}
</ul>
</div>
);
};
}
export default App;
and my League component
import React from 'react';
import Season from './Season';
class League extends React.Component {
state = {
seasons: {},
};
constructor(props) {
super(props);
}
componentDidMount() {
//this.getSeasonsAvailable(this.props.details.league_slug);
}
getSeasonsAvailable(league) {
const url = 'https://sportsop-soccer-sports-open-data-v1.p.mashape.com/v1/leagues/{league_slug}/seasons'.replace('{league_slug}',league);
const seasons = [];
console.log(this.props);
this.props.get(url).then((data) => {
data.seasons.map(function(object, i) {
seasons[data.seasons[i].identifier] = data.seasons[i];
});
this.setState({seasons: seasons});
});
};
render() {
const seasons = Object
.keys(this.state.seasons)
.map(key => <Season key={key} league_slug={this.props.details.league_slug} details={this.state.seasons[key]} />
);
return (
<li>
<span onClick={this.getSeasonsAvailable.bind(this.props.details.league_slug)}>{this.props.details.nation} : {this.props.details.name}</span>
<ul>
{seasons}
</ul>
</li>
);
}
static propTypes = {
get: React.PropTypes.func.isRequired
};
}
export default League;
When I click on the season component, I get this error :
Cannot read property 'get' of undefined
And my console.log(this.props) returns me undefined.
Thanks !
You just need to change
<span onClick={this.getSeasonsAvailable.bind(this.props.details.league_slug)}>
to
<span onClick={this.getSeasonsAvailable.bind(this, this.props.details.league_slug)}>
Apart from this, if you want to use ES6 way to do this. You can use arrow functions
<span onClick={() => this.getSeasonsAvailable(this.props.details.league_slug)}>
or you can bind the function getSeasonsAvailable in the constructor using
constructor() {
super();
this.getSeasonsAvailable = this.getSeasonsAvailable.bind(this);
}
You can read in more detail about it here and here.
Because your onClick: .bind(this.props.details.league_slug)
what is this.props.details.league_slug actually?
bind will change the reference of this in getSeasonsAvailable (this will ref to this.props.details.league_slug, I don't know what it is), of course you will get undefined when you call this.props
Try just .bind(this), so the this in getSeasonsAvailable can ref to the component itself.