trying to pass data from an api call to a component, but after the api call the data becomes undefined. im fairly new at react so any help would be greatly appreciated Thanks! all the classes are below, i didnt include the form componenet but it gets the data just fine
App.js
import React, { Component } from "react";
import axios from "axios";
import ShowtimeList from "./components/ShowtimeList";
import Form from "./components/Form";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
isFetching: true
};
this.getShowtimes = this.getShowtimes.bind(this);
}
getShowtimes(event) {
event.preventDefault();
const startDate = event.target.startDate.value;
const numDays = event.target.numDays.value;
const zipCode = event.target.zipCode.value;
const radius = event.target.radius.value;
const unit = event.target.units.value;
let showtimes = {};
const API_KEY = "<API-KEY>";
const call =
"http://data.tmsapi.com/v1.1/movies/showings?startDate=" +
startDate +
"&numDays=" +
numDays +
"&zip=" +
zipCode +
"&radius=" +
radius +
"&units=" +
unit +
"&api_key=" +
API_KEY;
this.setState({ isFetching: !this.state.isFetching });
axios
.get(call)
.then(function(response) {
console.log(response.data);
showtimes = response.data;
console.log(showtimes);
})
.catch(function(error) {
console.log(error);
});
}
renderShowtimes(showtimes) {
let times = "";
console.log(this.showtimes); ----- Undefined
if (this.showtimes != null) {
times = <ShowtimeList showtimes={this.showtimes} />;
} else {
times = "No Showtimes In Your Area";
}
return times;
}
render() {
return (
<div>
{this.state.isFetching ? (
<Form getShowtimes={this.getShowtimes} />
) : (
this.renderShowtimes()
)}
</div>
);
}
}
export default App;
ShowtimeList.js
import React, { Component } from "react";
import Showtime from "./Showtime";
class ShowtimeList extends Component {
render() {
return (
<ul>
{this.props.showtimes.map(showtime => {
return <Showtime showtime={showtime} />;
})}
</ul>
);
}
}
export default ShowtimeList;
Showtime.js
import React, { Component } from "react";
class Showtime extends Component {
render() {
return <li>{this.props.showtime}</li>;
}
}
export default Showtime;
Use state to store the showtimes and pass it down as props. Inside your state, add showtimes. Then inside your axios call instead of showtimes = response.data;, do a setState. this.setState({showtimes: response.data})
Then do <ShowtimeList showtimes={this.state.showtimes} />
You are not declaring the variable showtimes at the components scope, so that's why this.showtimes will always be undefined.
Anyway, I would recommend to store that data inside your component state.
Also in renderShowtimes you are asking for a showtime argument which you are not passing later when calling the function inside the render method.
You never set showtimes into your state. To fix this:
...
var _this = this;
axios
.get(call)
.then(function(response) {
console.log(response.data);
showtimes = response.data;
_this.setState({ showtimes: showtimes });
console.log(showtimes);
})
.catch(function(error) {
console.log(error);
});
...
Related
I'm newbie in React and trying to build a sample search filter with data from API. Unfortunately I have problem with this code.
It's get me an error ,,Cannot read property 'filter' of undefined".
It seems to me like child component doesn't get props from parent but I declared and imported this in code.
I've tried everything what I found on the internet but nothing helps. Can someone help me out with understanding what I made wrong?
Child
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Data from './Data';
class App extends Component {
constructor() {
super();
this.state = {
search : " "
};
}
updatedSearch(event) {
this.setState(
{search : event.target.value.substr(0,15)}
)
}
render () {
console.log(this.props.names)
let filterednames = this.props.names.filter(
(name) => {
return name.toLowerCase().indexOf(this.state.
search.toLowerCase()) !== -1;
}
);
return (
<div className = "App">
<h1> Users list </h1>
<Data />
<input type = "text"
placeholder = "Search by user name"
value = {this.state.search}
onChange = {this.updatedSearch.bind(this)}
/>
<ol>
{filterednames.map(name => (
<li key={name}>{name}</li>
))}
</ol>
</div>
)
}
}
ReactDOM.render(<App/>,document.getElementById('root'));
export default App;
Parent
import React, { Component } from 'react';
import App from './index';
class Data extends Component {
constructor(props) {
super(props);
this.state = {
names : [],
}
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users')
//Response
.then(response => response.json())
.then(output => {
let data = output;
//names in array
let listaimion = [];
for (let index = 0; index < data.length; index++) {
listaimion.push(data[index].name)
}
this.setState({names : listaimion})
})
}
render () {
return (
<div className = "Data">
<App names = {this.state.names} />
</div>
)
}
}
export default Data;
In the parent component, App needs to be declared. Also, App looks like your entry point of your application. Seems like, you might have mixed up Child and Parent here.
Parent -
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Data from './Data';
class App extends Component() {
constructor() {
this.state = {
names : [],
}
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users')
//Response
.then(response => response.json())
.then(output => {
let data = output;
let listaimion = [];
for (let index = 0; index < data.length; index++) {
listaimion.push(data[index].name)
}
this.setState({names : listaimion});
});
}
render () {
return (
<div className = "Data">
<Data names = {this.state.names} />
</div>
)
}
}
ReactDOM.render(<App/>,document.getElementById('root'));
export default App;
Child
import React, { Component } from 'react';
class Data extends Component {
constructor(props) {
super(props);
}
render() {
let filterednames = this.props.names.filter((name) => {
return name.toLowerCase().indexOf(this.state.
search.toLowerCase()) !== -1;
}
);
return (<div>{filterednames.join(',')}</div>)
}
}
The <App> component should be the parent - that is where your state should live. You would then pass this.state.names from <App> to <Data> inside the App render method. You should not import App inside Data - App should render Data.
// App.js
class App extends Component {
state = {
names: []
}
componentDidMount(){
// fetch data and when it's done use this.setState({ names: data })
}
render() {
return <Data names={this.state.names}/>
}
}
// Data.js
const Data = (props) => {
return props.names.map(() => {...your map function})
}
I can't get my api data from https://randomuser.me/api/
But when I'm using another api like http://dummy.restapiexample.com/api/v1/employees it works.
The error:
import React from "react";
import "./App.css";
import Start from "./start";
function App() {
return (
<div className="App">
<Start />
</div>
);
}
export default App;
start.js
import React, { Component } from "react";
import Axios from "axios";
class Start extends Component {
constructor(props) {
super(props);
this.state = {
results: []
};
}
componentDidMount() {
Axios.get("https://randomuser.me/api/").then(res => {
const results = res.data;
this.setState({ results });
console.log(results);
});
}
render() {
return (
<div>
{this.state.results.map(result => {
return <div>{result.id}</div>;
})}
</div>
);
}
}
export default Start;
Problem is that http://dummy.restapiexample.com/api/v1/employees returns array while https://randomuser.me/api/ returns object. Try changing to
componentDidMount() {
Axios.get("https://randomuser.me/api/").then(res => {
const results = res.data.results;
this.setState({ results });
console.log(results);
});
}
You have to use res.data.results. It comes in results object.
Please check your JSON data
last line you missed the "}]" typo error in http://dummy.restapiexample.com/api/v1/employees
componentDidMount() {
Axios.get("http://dummy.restapiexample.com/api/v1/employees").then(res => {
const results = res.data;
this.setState({ results: results });
});
}
I'm new to react and I am trying to fetch data from an API and pass the data to a child component. I've passed the data to the state on my parent component, however, when I pass it to the child component as props it logs as an empty array. I'm sure there is something simple I am overlooking but I don't know what, my code is below
PARENT COMPONENT
import React, {Component} from 'react';
import Child from '../src/child';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
properties: []
}
}
getData = () => {
fetch('url')
.then(response => {
return response.text()
})
.then(xml => {
return new DOMParser().parseFromString(xml, "application/xml")
})
.then(data => {
const propList = data.getElementsByTagName("propertyname");
const latitude = data.getElementsByTagName("latitude");
const longitude = data.getElementsByTagName("longitude");
var allProps = [];
for (let i=0; i<propList.length; i++) {
allProps.push({
name: propList[i].textContent,
lat: parseFloat(latitude[i].textContent),
lng: parseFloat(longitude[i].textContent)
});
}
this.setState({properties: allProps});
});
}
componentDidMount = () => this.getData();
render () {
return (
<div>
<Child data={this.state.properties} />
</div>
)
}
}
export default App;
CHILD COMPONENT
import React, {Component} from 'react';
class Child extends Component {
initChild = () => {
console.log(this.props.data); // returns empty array
const properties = this.props.data.map(property => [property.name, property.lat, property.lng]);
}
componentDidMount = () => this.initChild();
render () {
return (
<div>Test</div>
)
}
}
export default Child;
Change the componentDidMount in the child to componentDidUpdate.
The componentDidMount lifecycle method is called only once in the starting. Whereas, the componentDidUpdate lifecycle method gets called whenever there is a change in the state of the application. Since api calls are asynchronous, the initChild() function is already called once before the api call's results are passed to the child.
You can use conditional rendering
import React, {Component} from 'react';
class Child extends Component {
initChild = () => {
if(this.props.data){
const properties = this.props.data.map(property => [property.name, property.lat, property.lng]);
}
}
componentDidMount = () => this.initChild();
render () {
return (
<div>Test</div>
)
}
}
export default Child;
I've got a function in my React app that is calling in componentWillMount lifecycle method.
It grabs data from JSON file and push it to the component's state (it is a text data, I later insert that text into the page).
I'm going to use the same function on many other components, can I separate this function into a separate component to make it reusable?
Here is my code:
import React from 'react';
import axios from 'axios';
import logo from '../img/company_logo.png';
import '../css/header.scss';
import getTextData from './getTextData';
const NumberList = (props) => {
console.log(props.value);
const itemList = props.value;
const listItems = itemList.map(number => (
<li key={number.toString()}>
{number}
</li>
));
return (
<ul>{listItems}</ul>
);
};
export default class Header extends React.Component {
constructor() {
super();
this.state = {};
}
componentWillMount() {
axios.get('./data.json')
.then((res) => {
this.setState({
siteData: res.data,
});
})
.catch((err) => {
console.log(err);
});
}
render() {
// console.log(this.state);
const { siteData } = this.state;
if (siteData) {
console.log(siteData.data.mainPage.navBar);
} else {
return null;
}
return (
<div className="headerWrapper">
<img src={logo} alt="company_logo" id="companyLogo" />
<NumberList value={siteData.data.mainPage.navBar} />
</div>
);
}
}
Yes, create a function and return the repsonse-data, must use async await
//fetchService.js
import axios from 'axios';
export default async function fetchService(){
let responseData = [];
await axios.get('./data.json')
.then((res) => {
responseData = res.data;
})
.catch((err) => {
console.log(err);
});
return responseData;
}
// App.js
import fetchService from './fetchService';
async componentDidMount() {
let tempData = await fetchService();
this.setState({
siteData: tempData,
});
}
i hope this helps!
I'm trying to use flickr api to fetch public photos and create an image carousel with them but seems it does not want to get photos in the beginning. Since I'm new to React, it is really hard to figure out what I'm doing wrong here so any kinda help will be appreciated.. Thank you.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import _ from 'lodash';
import Button from './components/button';
const urlArr = [];
const apiKey = "YOUR_API";
const userId = "YOUR_ID";
const url = `https://api.flickr.com/services/rest/?method=flickr.people.getPublicPhotos&api_key=${apiKey}&user_id=${userId}&format=json&nojsoncallback=1`;
class App extends Component {
constructor(props) {
super(props);
this.state = { urlArr: [] };
axios.get(url)
.then(function(photoData) {
_.forEach(photoData.data.photos.photo, (photo) => {
// this.setState({ urlArr: `https://farm6.staticflickr.com//${photo.server}//${photo.id}_${photo.secret}_z.jpg` });
urlArr.push(`https://farm6.staticflickr.com//${photo.server}//${photo.id}_${photo.secret}_z.jpg`);
});
this.setState({ urlArr });
});
}
render() {
return (
<div>
<Button />
</div>
);
}
};
ReactDOM.render(<App/>, document.querySelector('.container'));
Code above returns 'TypeError: Cannot read property 'setState' of undefined' and I'm not quite sure what that means..
You're calling the setState() in a callback function of a Promise.
The error is because the this is not the React Component.
You should use an arrow function or bind the React Component instance to your callback function.
For example:
axios.get(url)
.then((photoData) => {
_.forEach(photoData.data.photos.photo, (photo) => {
// this.setState({ urlArr: `https://farm6.staticflickr.com//${photo.server}//${photo.id}_${photo.secret}_z.jpg` });
urlArr.push(`https://farm6.staticflickr.com//${photo.server}//${photo.id}_${photo.secret}_z.jpg`);
});
this.setState({ urlArr });
});
Or:
axios.get(url)
.then(function(photoData) {
_.forEach(photoData.data.photos.photo, (photo) => {
// this.setState({ urlArr: `https://farm6.staticflickr.com//${photo.server}//${photo.id}_${photo.secret}_z.jpg` });
urlArr.push(`https://farm6.staticflickr.com//${photo.server}//${photo.id}_${photo.secret}_z.jpg`);
});
this.setState({ urlArr });
}.bind(this));