Skip to main content

10.08 Retrieving Data From Backend

BurgerBuilder.js

BurgerBuilder.js
import React, { Component, Fragment } from "react";
import axios from "../../axios-orders";
import BuildControls from "../../components/Burger/BuildControls/BuildControls";
import Burger from "../../components/Burger/Burger";
import OrderSummary from "../../components/Burger/OrderSummary/OrderSummary";
import Modal from "../../components/UI/Modal/Modal";
import Spinner from "../../components/UI/Spinner/Spinner";
import withErrorHandler from "../../hoc/withErrorHandler/withErrorHandler";

const INGREDIENT_PRICES = {
salad: 0.5,
cheese: 0.4,
meat: 1.3,
bacon: 0.7,
};

class BurgerBuilder extends Component {
// constructor(props) {
// super(props);
// this.state = {...}
// }
state = {
ingredients: null,
totalPrice: 4,
purchasable: false,
purchasing: false,
loading: false,
error: false,
};

componentDidMount() {
axios
.get(
"https://react-burger-bf7e8-default-rtdb.europe-west1.firebasedatabase.app/ingregients.json"
)
.then((response) => {
this.setState({ ingredients: response.data });
})
.catch((error) => {
this.setState({ error: true });
});
}

updatePurchaseState(ingredients) {
const sum = Object.keys(ingredients)
.map((igKey) => {
return ingredients[igKey];
})
.reduce((sum, el) => {
return sum + el;
}, 0);
this.setState({ purchasable: sum > 0 });
}

addIngredientHandler = (type) => {
const oldCount = this.state.ingredients[type];
const updateCount = oldCount + 1;
const updatedIngredients = {
...this.state.ingredients,
};
updatedIngredients[type] = updateCount;
const priceAddition = INGREDIENT_PRICES[type];
const oldPrice = this.state.totalPrice;
const newPrice = oldPrice + priceAddition;
this.setState({ totalPrice: newPrice, ingredients: updatedIngredients });
this.updatePurchaseState(updatedIngredients);
};

removeIngredientHandler = (type) => {
const oldCount = this.state.ingredients[type];
if (oldCount <= 0) {
return;
}
const updateCount = oldCount - 1;
const updatedIngredients = {
...this.state.ingredients,
};
updatedIngredients[type] = updateCount;
const priceDeduction = INGREDIENT_PRICES[type];
const oldPrice = this.state.totalPrice;
const newPrice = oldPrice - priceDeduction;
this.setState({ totalPrice: newPrice, ingredients: updatedIngredients });
this.updatePurchaseState(updatedIngredients);
};

purchaseHandler = () => {
this.setState({ purchasing: true });
};

purchaseCancelHandler = () => {
this.setState({ purchasing: false });
};

purchaseContinueHandler = () => {
// alert("You continue!");
this.setState({ loading: true });
const order = {
ingredients: this.state.ingredients,
price: this.state.totalPrice,
customer: {
name: "Pash Pa",
address: {
street: "Teststreet 1",
zipCode: "34234",
country: "Russia",
},
email: "test@test.com",
},
deliveryMethod: "fastest",
};
axios
.post("/orders.json", order)
.then((response) => {
this.setState({ loading: false, purchasing: false });
})
.catch((error) => {
this.setState({ loading: false, purchasing: false });
});
};
render() {
const disabledInfo = {
...this.state.ingredients,
};

for (let key in disabledInfo) {
disabledInfo[key] = disabledInfo[key] <= 0;
}
let orderSummary = null;

let burger = this.state.error ? (
<p>Ingredients can't be loaded!</p>
) : (
<Spinner />
);

if (this.state.ingredients) {
burger = (
<Fragment>
<Burger ingredients={this.state.ingredients} />
<BuildControls
ingredientAdded={this.addIngredientHandler}
ingredientRemoved={this.removeIngredientHandler}
disabled={disabledInfo}
purchasable={this.state.purchasable}
ordered={this.purchaseHandler}
price={this.state.totalPrice}
/>
</Fragment>
);

orderSummary = (
<OrderSummary
ingredients={this.state.ingredients}
purchaseCancelled={this.purchaseCancelHandler}
purchaseContinued={this.purchaseContinueHandler}
price={this.state.totalPrice}
/>
);
}
if (this.state.loading) {
orderSummary = <Spinner />;
}
return (
<Fragment>
<Modal
show={this.state.purchasing}
modalClosed={this.purchaseCancelHandler}
>
{orderSummary}
</Modal>
{burger}
</Fragment>
);
}
}
export default withErrorHandler(BurgerBuilder, axios);

withErrorHandler.js

caution

The fix is simple, here I'll use componentWillMount. However, in the future, this React lifecycle hook or lifecycle method will not be supported anymore and therefore you can also just use the constructor because the general idea here is that we execute this code when this component here gets created and with that, I mean that component object and of course the constructor also runs when this gets created, so, therefore using the constructor instead of componentWillMount will work in exactly the same way.

withErrorHandler.js
import React, { Component, Fragment } from "react";
import Modal from "../../components/UI/Modal/Modal";

const withErrorHandler = (WrapperComponent, axios) => {
return class extends Component {
state = {
error: null,
};
componentWillMount() {
axios.interceptors.request.use((req) => {
this.setState({ error: null });
return req;
});
axios.interceptors.response.use(
(res) => res,
(error) => {
this.setState({ error: error });
}
);
}

errorConfirmedHandler = () => {
this.setState({ error: null });
};

render() {
return (
<Fragment>
<Modal
show={this.state.error}
modalClosed={this.errorConfirmedHandler}
>
{this.state.error ? this.state.error.message : null}
</Modal>
<WrapperComponent {...this.props} />;
</Fragment>
);
}
};
};

export default withErrorHandler;