Connecting the component to the store

We are now at the point where we have a working component on the product page. However, the amount of loyalty points that is shown is static. We need to connect the component to our Redux store to get the correct amount for each product.

To do this we need to:

  • Create a selector to get the data from the store
  • Create a connector to map the data to component props
  • Adjust the component to use the connector

Creating the selector

Selectors are an efficient way of retrieving data from a store. You can read more about selectors from the Reselect documentation.

The selector will return the value of the loyaltyPoints field from the current product. If there is no value present, it will default to null.

It is good practice to create selectors that return a predictable value when data is unavailable. This will make it easier for React components to know what to render when they receive this value. React will treat a value of null as non-existing and will fallback to the default value of the prop.

We need to create a new file called selectors.js inside the Loyalty directory at
<theme-root>/pages/Product/components/Header/components/Loyalty.

The contents of this file should be the following:

<theme-root>/pages/Product/components/Header/components/Loyalty/selectors.js
import { createSelector } from 'reselect';
import { getCurrentProduct } from '@shopgate/pwa-common-commerce/product/selectors/product';

export const getProductLoyaltyPoints = createSelector(
  getCurrentProduct,
  product => product ? product.loyaltyPoints : null
);

Creating the connector

A connector is a component wrapper that will inject props from a redux store into a component. You can read more about connectors from the React Redux documentation.

We need to create a new file inside our component directory called connector.jsat
<theme-root>/pages/Product/component/Header/components/Loyalty.

Now we can use the previously created selector to inject the correct amount of loyalty points into the points prop of our component:

<theme-root>/pages/Product/component/Header/components/Loyalty/selector.js
import { connect } from 'react-redux';
import { getProductLoyaltyPoints } from './selectors';

const mapStateToProps = state => ({
  points: getProductLoyaltyPoints(state),
});

export default connect(mapStateToProps, null);

Adjusting the Loyalty component

Finally, we need to adjust our Loyalty component to use the connector.

To do this, we need to import the connector and wrap the default export with the connect() function:

<theme-root>/pages/Product/component/Header/components/Loyalty/index.jsx
import React from 'react';
import PropTypes from 'prop-types';
import LoyaltyIcon from 'Components/icons/LoyaltyIcon';
import I18n from '@shopgate/pwa-common/components/I18n';
import styles from './style';
import connect from './connector';

const Loyalty = ({ points }) => (
  points ? (
    <div className={styles.container}>
      <LoyaltyIcon className={styles.icon} />
      <I18n.Text string="product.loyalty" />: {points}
    </div>
  ) : null
);

Loyalty.propTypes = {
  points: PropTypes.number,
};

Loyalty.defaultProps = {
  points: 0,
};

export default connect(Loyalty);

Now the points that are displayed will reflect the appropriate value for this product.