Connecting ProductPage to the store

In this section, we'll connect the ProductPage component to our store:

  1. Let's first import the following into ProductPage.tsx:
import { connect } from "react-redux";
import { addToBasket } from "./BasketActions";
import { getProduct } from "./ProductsActions";
import { IApplicationState } from "./Store";
  1. We are going to reference the store's getProduct now and not the one from ProductsData.ts. So, let's remove this from this import so that it looks like the following:
import { IProduct } from "./ProductsData";
  1. Next, let's move the state into props:
interface IProps extends RouteComponentProps<{ id: string }> {
addToBasket: typeof addToBasket;
getProduct: typeof getProduct;
loading: boolean;
product?: IProduct;
added: boolean;
}

class ProductPage extends React.Component<IProps> { ... }

So, the IState interface and the Props type should be removed after this movement.

  1. We can remove the constructor as we don't need to initialize any state now. This is all done in the store.
  2. Let's change the componentDidMount life cycle method to call the action creator for getting the product:
public componentDidMount() {
if (this.props.match.params.id) {
const id: number = parseInt(this.props.match.params.id, 10);
this.props.getProduct(id);
}
}

Notice that we also remove the async keyword because the method is no longer asynchronous.

  1. Moving on to the render function, let's replace the references to state with references to props:
public render() {
const product = this.props.product;
return (
<div className="page-container">
<Prompt when={!this.props.added} message={this.navAwayMessage}
/>
{product || this.props.loading ? (
<Product
loading={this.props.loading}
product={product}
inBasket={this.props.added}
onAddToBasket={this.handleAddClick}
/>
) : (
<p>Product not found!</p>
)}
</div>
);
}
  1. Let's look at the click handler now and refactor it to call the action creator for adding to the basket:
private handleAddClick = () => {
if (this.props.product) {
this.props.addToBasket(this.props.product);
}
};
  1. On to the final few steps now in the connection process. Let's implement the function that maps the action creators from the store into the component props:
const mapDispatchToProps = (dispatch: any) => {
return {
addToBasket: (product: IProduct) => dispatch(addToBasket(product)),
getProduct: (id: number) => dispatch(getProduct(id))
};
};
  1. Mapping the state to the component props is a little more complex. Let's start with the simple mappings:
const mapStateToProps = (store: IApplicationState) => {
return {
basketProducts: store.basket.products,
loading: store.products.productsLoading,
product: store.products.currentProduct || undefined
};
};

Note that we map a null currentProduct to undefined.

  1. The remaining prop we need to map to is added. We need to check whether the current product in the store is in the basket state in order to set this boolean value. We can use the some function in the products array for this:
const mapStateToProps = (store: IApplicationState) => {
return {
added: store.basket.products.some(p => store.products.currentProduct ? p.id === store.products.currentProduct.id : false),
...
};
};
  1. The last step is to use the connect HOC from React Redux to wire the ProductPage component to the store:
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProductPage);

We can now go to the running app, visit the product page, and add it to the basket. The Add to basket button should disappear after it is clicked. If we browse to a different product and then come back to a product we've already added to the basket, the Add to basket button shouldn't be present.

So, we now have both the Products and Product pages connected to our Redux store. In the next section, we'll create a basket summary component and connect that to the store.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.94.171