Refactor Checkout.js
The checkout page uses multiple API calls to correctly display the items a product manager wants to ship to stores.
Refactor the Checkout.js
file#
As we progress through this module's lesson, each component we touch takes the refactoring complexity up a notch, and the <Checkout>
component is no different.
Whereas the <App>
component had just one lifecycle method and API call, this component has multiple API calls being triggered in different ways. We'll need to account for all of them.
We will learn how to handle converting multiple API calls and functions in this lesson while we convert Checkout.js
.
But we can handle this. We'll follow the recipe and knock it out, no sweat.
Convert checkout to a functional component, and remove its render method#
In what should be becoming a familiar refrain to you, we'll start by converting this class-based <Checkout>
component into a function-based component.
This class declaration on line 14 of the Checkout.js
file located on the file path client/src/containers/Checkout/
is the first thing to focus on.
class Checkout extends Component {
Update that line to be:
const Checkout = () => {
And then delete the render
method and object destructuring right before the JSX rendering — they're unnecessary.
render() {
const { checkoutItems, loading, error } = this.state;
const { removeItemFromCheckout } = this;
Don't forget the curly brace at the end of the JSX statement as well.
It's safe now to delete the React
and destructured Component
imports on line 1 of this file.
import React, { Component } from 'react';
They'll be replaced with useState
and useEffect
in this first import instead.
import { useEffect, useState } from 'react';
Replace the component's class state with useState
Hooks#
Our next move is to update the state for this component. Since <Checkout>
has both state and props, we'll be replacing the state with useState
variables and destructuring the props in this section.
Our component starts out with this state:
constructor(props) {
super(props);
this.state = {
checkoutItems: [],
loading: true,
error: false,
};
}
And this prop from its parent <App>
component.
await this.props.updateCheckoutCount();
Those two pieces of code will become:
const Checkout = ({ updateCheckoutCount }) => {
const [checkoutItems, setCheckoutItems] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
Now we've got our individually declared pieces of state, and we've brought the updateCheckoutCount
function being passed as a prop from the <App>
parent component into this functional component with object destructuring.
And we'll update where this function is called in the code, too.
await updateCheckoutCount();
Nice. Time to start updating the lifecycle methods in this component.
Prop destructuring is not mandatory
Throughout this course, you'll see me destructuring nested objects being passed as props. I do this not only because it's an ESLint error but also because I think it makes the code cleaner and easier to read.
If you, however, prefer to import all the props and then access the values inside of the component, that's fine too.
Your function's import and access to those props will look very similar to any other functional component you've ever worked with.
1const Checkout = (props) => {2// some code
3props.updateCheckoutCount();4};
Fetch checkout items with useEffect
#
<Checkout>
component's got a componentDidMount
function to fetch any products in the checkout when it first mounts in the DOM via the checkout API.
Our componentDidMount
method looks like this:
async componentDidMount() {
const checkoutItems = await checkoutApi.getAllCheckoutItems();
if (checkoutItems !== FETCH_CHECKOUT_PRODUCTS_ERROR) {
this.setState({ checkoutItems, loading: false, error: false });
} else {
this.setState({ loading: false, error: true