Reputation: 131
I have a parent component called Home.js which retrieves the data from an API and send the data as a property to it's child component DishItem.js that shows the dish details. I am trying to render the dish_name, quantity (that can be changed) and net_cost, and I am storing all of these in a state and setting their state for the initial render through componentWillMount() lifecycle method. But it fails to set the state and returns undefined.
Home.js
import React, { Component } from 'react';
import DishItem from './DishItem';
import $ from 'jquery';
export default class Home extends Component {
constructor() {
super();
this.state = {
dish: ''
}
}
getDishes() {
$.ajax({
url: 'http://testbed2.riktamtech.com/foody_buddy/public/api/dishes/dish/31816',
dataType: 'json',
cache: false,
success: function(response) {
this.setState({dish: response.data});
}.bind(this),
error: function(xhr, status, err) {
console.log(err);
}
});
}
componentWillMount() {
this.getDishes();
}
componentDidMount() {
this.getDishes();
}
render() {
return (
<div className="Home">
<DishItem dish={this.state.dish}/>
</div>
);
}
}
DishItem.js
import React, { Component } from 'react';
import Quantity from './Quantity';
import { browserHistory } from 'react-router';
import './style.css';
export default class DishItem extends Component {
constructor(props) {
super(props);
this.state = {
quantity: 1,
delivery: '',
total_cost: '',
net_cost: null,
counter: 1
}
}
componentWillMount() {
console.log(this.props.dish.net_cost); //undefined instead of some value
this.setState({net_cost: this.props.dish.net_cost});
console.log(this.state.net_cost); // null
}
handleChangeInQuantity(value) {
var net_cost = 0;
var total_cost = 0;
total_cost = value * this.props.dish.cost;
net_cost = value * this.props.dish.net_cost;
this.setState({quantity: value, net_cost: net_cost, total_cost: total_cost});
}
saveAndContinue(e) {
e.preventDefault();
}
render() {
let address = <div>{this.props.dish.address}<br/>{this.props.dish.landmark}<br/>{this.props.dish.locality}</div>
return (
<div>
<h3>{this.props.dish.name}<small>{this.props.dish.description}</small></h3>
Total- {this.state.net_cost}
<Quantity change_in_quantity={this.handleChangeInQuantity.bind(this)} />
<button className="btn btn-default" onClick={this.saveAndContinue.bind(this)}>Next</button>
</div>
);
}
}
Upvotes: 0
Views: 1881
Reputation: 822
it seems that I can't add a comment so I will just send this since there are already many answers. Please don't give me minus one because of this :)
Even though it is in componentDidMount, once it fetches the data, it will re-render the DOM so it will look like it is the initial render. If the fetching is slow, you will see it blank for a moment and then renders to what you need it to be.
If you really really need to make it show up at the very first moment, I suggest that you fetch the data and save it inside Flux store or Redux store before redirecting to this page. For example, fetch the data and do the redirection inside then() or callback function.
Upvotes: 1
Reputation: 20236
You should not use the componentWillMount
method of a React component to do asynchronous data fetching. Remove your call to the getDishes
method and leave it in componentDidMount
. In the render
method of your Home component, check if the state already has the dish data in the state. If it doesn't, don't render the DishItem component. You can put a "Please wait, loading" message or something like that instead.
When the page is loaded, React will render the component with the "loading " message and start loading the dish data asynchronously. When the data is done loading and the state is set, React will render the component again with the DishItem component.
Here's an updated version of your Home component:
import React, { Component } from 'react';
import DishItem from './DishItem';
import $ from 'jquery';
export default class Home extends Component {
constructor() {
super();
this.state = {
dish: null
};
}
getDishes() {
$.ajax({
url: 'http://testbed2.riktamtech.com/foody_buddy/public/api/dishes/dish/31816',
dataType: 'json',
cache: false,
success: function (response) {
this.setState({ dish: response.data });
}.bind(this),
error(xhr, status, err) {
console.log(err);
}
});
}
componentDidMount() {
this.getDishes();
}
render() {
return (
<div className="Home">
{
this.state.dish === null ?
<div>Please wait, loading…</div> :
<DishItem dish={this.state.dish} />
}
</div>
);
}
}
Upvotes: 1
Reputation: 509
componentWillMount() function is triggered only once, it does not wait to get the data from the server. you should use componentWillReceiveProps() in the DishItem component, and set the new state with the data sent from the Home component to it. This way whenever the DishItem receives new props from the Home component, it will update accordingly.
Upvotes: 2