I have an api which i want to filter the data and place the filterd into a state
export default class ModifyPage_Single extends React.Component {
constructor(props) {
super(props)
this.state = {data:[],idd:""}
}
componentWillMount() {
fetch("removed api")
.then(response => response.json())
.then((data) =>{
this.setState({data:data})
})
}
render() {
const test = this.state.data.map((e) => { if(e.ID === this.props.location.productdetailProps.productdetail) {this.setState({idd:e.PP})} })
But i keep getting this error Unhandled Rejection (Error): Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
How can i solve so that the fitered out api goes into the state?
Thanks in advance
you should update in componentMount, not in render():
export default class ModifyPage_Single extends React.Component {
constructor(props) {
super(props);
this.state = { data: [], idd: "" };
}
componentWillMount() {
fetch("removed api")
.then((response) => response.json())
.then((data) => {
this.setState({ data: data });
data.forEach((e) => {
if (e.ID === this.props.location.productdetailProps.productdetail) {
this.setState({ idd: e.PP });
}
});
});
}
render() {
return null;
}
}
You can update the state in lifecycle methods, updating it in render is anti pattern
componentDidMount() {
fetch("removed api")
.then(response => response.json())
.then((data) =>{
this.setState({data:data})
const iddObj = data.find((el) => el.ID === this.props.location.productdetailProps.productdetail)
if(iddObj ){
this.setState({idd:iddObj.PP})
}
})
}
Related
Here is my React js code for a single API call for a date range picker. now I want to call multiple API in React with componentDidMount Method is it possible if yes how can do that
import React,{ Component} from "react";
import axios from 'axios'
class PostList extends Component{
constructor(props) {
super(props)
this.state = {
posts: []
}
}
componentDidMount(){
axios.get('http://127.0.0.1:8000/betweendays')
.then(response => {
this.setState({
posts:response.data
})
console.log(response.data)
})
}
render() {
const {posts} = this.state
return (
<div>
<h1>get call in React js</h1>
{
posts.map(post => <div key = {post.id}>{post.id} </div>)
}
</div>
)
}
}
export default PostList```
Using .then() method to create chain of the requests..
componentDidMount() {
axios.get('http://127.0.0.1:8000/betweendays')
.then(response => {
this.setState({
posts: response.data
})
return response.data; // returning response
})
.then(res => {
// do another request Note we have the result from the above
// getting response returned before
console.log(res);
})
// Tag on .then here
.catch(error => console.log(error))
}
You can add more apis in componentDidMount as u want.
componentDidMount(){
axios.get('http://127.0.0.1:8000/betweendays')
.then(response => {
this.setState({
posts:response.data
})
console.log(response.data)
})
axios.get('link')
.then(response => {
this.setState({
posts:response.data
})
console.log(response.data)
})
}
i'm getting absolutely no response from calling my api in react:
constructor(props) {
super(props);
this.state = {
team: {}
}
}
getData() {
axios.get('http://game.test/api/characters')
.then(response => this.setState({ team: response.data.characters }));
}
componentDidMount() {
this.getData();
console.log(this.state);
}
the state is empty and if I console.log anything in .then, the console is also empty (like that part of the code is not reachable).
Also on Network tab everything seems to be okay (status 200 & correct data).
setState is async so in console.log(this.state) will execute before this.getData() in the componentDidMount. if you want to log the fetch result/error put log in getData with async/await:
constructor(props) {
super(props);
this.state = {
team: {},
error: ""
}
}
getData = async () => {
await axios.get('http://game.test/api/characters')
.then(response => this.setState({ team: response.data.characters }))
.catch(error => this.setState({error: error}))
console.log(this.state) //log fetch result/error
}
componentDidMount() {
this.getData();
console.log(this.state) //log init state
}
Try this, it will work
App.js
import Child from "./Comp/Chid";
export default function App() {
return (
<div className="App">
<Child />
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
Comp/Child.js
import React from "react";
import axios from "axios";
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
team: {}
};
}
async getData() {
await axios
.get("https://jsonplaceholder.typicode.com/posts")
.then((response) => {
console.log(response);
this.setState({ team: response.data.characters });
});
}
componentDidMount() {
this.getData();
console.log(this.state);
}
render() {
return <div>Hello</div>;
}
}
export default Child;
i dont see much problem with your code try the following if it helps
first try to console.log(response) before updating the state
try async getData () and await axios since you are fetching asynchronous operation
I have the previous code that updates the interval data in the locale and in the browser without issue.
class Main extends Component {
constructor(props) {
super(props);
this.state = {data: []}
}
componentWillMount() {
fetch('file.json')
.then(response => response.json())
.then(result =>
this.setState({
data: result.data}));
}
componentDidMount() {
this.timer = setInterval(() => componentWillMount(), 5000);
}
componentWillUnmount() {
this.timer = null;
}
Due to the fact that componentWillMount is now deprecated for use, I decided to rewrite the code. As a result, the data is updated in the locale, but not in the browser. Why? Please help me.
class Main extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
lang: 'ru'
}
}
componentDidMount() {
this.loadingData = fetch('file.json')
.then(response => response.json())
.then(result =>
this.setState({
data: result.data}));
this.timer = setInterval(() => this.loadingData, 5000);
}
componentWillUnmount() {
this.timer = null;
}
As requested, here's an answer based on my comment. Also see how I clear the interval when the component will be unmounted.
class Main extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
lang: 'ru'
}
}
loadData() {
fetch('file.json')
.then(response => response.json())
.then(result =>
this.setState({
data: result.data
})
);
}
componentDidMount() {
this.loadData();
this.timer = setInterval(() => this.loadData(), 5000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
You may consider to use setTimeout and reinitiate this from within your fetch so that you can account for slow network etc.
I am not sure if this is the "right" way to do it but you can just force the browser to refresh the page: window.location.reload()
I'm making a call to a getTime function which returns the datetime, but for some reason the state I specify is not being updated, am I misunderstanding how this works? Do I need to await the result?
import * as React from 'react';
import {getTime} from '../utilities/time-helper'
export default class Landing extends React.Component {
constructor(props) {
super(props);
this.state = {
london: null,
paris: null
};
}
componentDidMount() {
this.setState({ london: getTime("Europe/London") });
this.setState({ paris: getTime("Europe/Paris") });
}
render() {
return (
<div>
<h1>London Time: {this.state.london}</h1>
<h1>Paris Time: {this.state.paris}</h1>
</div>
);
}
}
// time-helper.js
export function getTime(timezone) {
let url = 'http://worldtimeapi.org/api/timezone/' + timezone;
fetch(url)
.then(res => res.json())
.then((out) => {
return out.datetime
})
.catch(err => { throw err });
}
Yes, exactly, it's a fetch, so you gotta wait for the result and set the state only then, so you could do smth like:
componentDidMount() {
getTime('Europe/London')
.then((response) => this.setState({ london: response });
}
I have problem with sending information from one component child to parent and from parent to other component. There is 3 components main (App.js), and two child (MoviePoster.js and MovieDescription.js). In App.js we have state named ID. I send function with setState to MoviePoster where I use it in onClick. Function seting id to our state. App.js send props with id to MovieDescription. In MovieDescription I use API to download information about film based on his ID. Clicking on MoviePoster should change ID and send to MovieDescription, after that MovieDescription should render information about this film. I must click three times on MoviePoster to render new information about film and i can't understand why it's working after third click and doesn't work after first click. Here is my code:
App.js
First I tried to save all information from API to couple of states. But in the end it causes inifinite loop with rendering the elements. So I change state to global variables.
Second I tried to put downloading from API to Component Life Circle Methods like in code.
class App extends Component {
constructor(props) {
super(props)
this.updateId = this.updateId.bind(this)
}
state = {
response: '',
post: '',
responseToPost: '',
id: 438808
};
updateId = (id) => {
this.setState({id: id})
}
render() {
return (
<div className="App">
<MoviePoster updateId = {this.updateId} />
<MovieDescription id = {this.state.id} />
</div>
);
}
}
MoviePoster.js
class MoviePoster extends React.Component{
state = {
images: [],
title: []
}
handleImgClick = (id) => {
this.props.updateId(id);
}
componentDidMount(){
this.getMovie();
}
getMovie = ()=>{
axios.get('https://api.themoviedb.org/3/movie/upcoming?api_key=332654c71ccbb479020bcc047eaa43e8&language=en-US&page=1®ion=pl')
.then(res=>{
this.setState({
images: res.data.results.slice(0,4)
})
})
}
render(){
const { images } = this.state;
const posters = images.map( image => {
return(
<div onClick={() => this.handleImgClick(image.id)} className='poster-con'key={image.id}>
<div className='poster-s-con' >
<img className="poster responsive-img" src ={`http://image.tmdb.org/t/p/w300${image.poster_path}`} alt='img'/>
<h5 className='movie-title'>{image.title}</h5>
</div>
</div>
)
})
return(
<div className='movie-big-con white-text'>
<div className='movie-small-con'>
<div className='movie-con'>{posters}</div>
</div>
</div>
)}
};
export default MoviePoster;
MovieDescription.js
let data = {};
let data1 = {};
class MovieDescription extends React.Component {
componentWillMount() {
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}?api_key=${api_key}&language=en-US`)
.then(response => response.json())
.then(json => {
data = json;
});
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}/credits?api_key=${api_key}`)
.then(response => response.json())
.then(json => {
data1 = json;
});
}
componentWillUpdate() {
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}?api_key=${api_key}&language=en-US`)
.then(response => response.json())
.then(json => {
data = json;
});
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}/credits?api_key=${api_key}`)
.then(response => response.json())
.then(json => {
data1 = json;
});
}
render() {
return(
<div>{data.overview}</div>
<div>{data.runtime}</div>
);
}
}
I want to click once on poster and have rerendered component MovieDescription with new content download from API. I dont have idea what is wrong.
The best part in react is state which you are not utilizing it in MovieDescription component so move data and data1 variables under component state so that whenever you do setState the component will re render with updated data. With your current MovieDescription component code though you do fetch calls assign data to variables won’t re render the component because you are overriding a variable so it won’t trigger re render.
Also use componentDidMount instead of componentWillMount method. As you know componentWillMount is deprecated in react v16 version.
Here is the updated MovieDescription component code
class MovieDescription extends React.Component {
constructor(props){
super(props);
this.state = {
data:{},
data1: {}
}
}
componentDidMount() {
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}?api_key=${api_key}&language=en-US`)
.then(response => response.json())
.then(json => {
this.setState({data : json});
});
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}/credits?api_key=${api_key}`)
.then(response => response.json())
.then(json => {
this.setState({data1: json});
});
}
componentWillUpdate() {
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}?api_key=${api_key}&language=en-US`)
.then(response => response.json())
.then(json => {
this.setState({data : json});
});
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}/credits?api_key=${api_key}`)
.then(response => response.json())
.then(json => {
this.setState({data1 :json});
});
}
render() {
return(
<div>{data.overview}</div>
<div>{data.runtime}</div>
);
}
}
in MovieDescription, put the data objects in the state. when you get the json back from the fetches uses setState({}) to update the data. I think that should fix your problem. Ideally you would do all of this in the main component and pass the data as props to the child components. That way you don't have to worry about the states in three objects, just one.