Configure a widget to use REST endpoints

Once you have created a custom widget, you can update your application to communicate with the REST API.

To continue creating the widget code that displays a list of currencies, you must obtain the location from which the data should be retrieved. For this example, assume that you get the data from the Redux store. First, you must declare the component. Do this by exporting a connect component. It acts as a wrapper around your component and lets you connect your component to a specific part of the state located in the Redux store. This allows properties to be passed in as props to your component. Then you pass a selector that points to a specific part of the Redux store into the constructor for that component. Whenever those properties change, your component will re-render. The connect component binds the display of your component to the values of your properties.

This is how your component obtains data. You can also use the connect component to perform specific tasks, which might result in updates to the data in the Redux store. This would result in re-rendering certain parts of your application.

This is an example of the widget’s /plugin/components/currency-selector/index.js file where the wrapped component is identified:
/**
 * Wrap the component with a "connect" object that supplies the state's
 * currency information as props and redisplays the component when any of those
 * props change.
 */
 export default connect(getCurrencyInfo)(CurrencySelector);

When you create a widget that may have significant differences between user interfaces, it is recommended that you create separate widgets.

In the following code, the HTML looks up the currencies array. Then it takes the given currency and adds options using the displayName of the given currency. This is defined in the /plugin/components/currency-selector/index.js file.

Once you have configured your widget to use endpoints, this is what the index.js file for the currency selector should resemble:
import React, {useContext} from 'react';
import {StoreContext} from '@oracle-cx-commerce/react-ui/contexts';
import Styled from '@oracle-cx-commerce/react-components/styled';
import {connect} from '@oracle-cx-commerce/react-components/provider';
import css from './styles.css';
import {getCurrencyInfo} from '../../selectors';
import {listCurrenciesFetcher} from '../../fetchers';
import {useListCurrenciesFetcher} from '../../fetchers/hooks';
 
// The server-side rendering framework checks each component for a "fetchers" array
// to determine what actions to take in order to populate the initial state. For this
// component, we need the currency list.
export const fetchers = [listCurrenciesFetcher];
 
/**
 * The CurrencySelector component.
 *
 * @param {object} props.currencies Array of info about available currencies
 * @param {object} props.selectedCurrency Info about the selected currency
 * @param {string} props.label* Resource strings
 */
const CurrencySelector = ({
  currencies,
  selectedCurrency,
  labelCurrencies,
  labelSelectACurrency,
  labelSelectedCurrency
}) => {
  // Make sure we have the latest currency list during client-side rendering.
  const store = useContext(StoreContext);
  useListCurrenciesFetcher(store);
 
  // Invoked when the user selects a currency from the
  // select element. Invokes the '_getCurrency' action to
  // update the selected currency with info from the server.
  const onCurrencyChange = event => {
    const repositoryId = event.target.value;
    if (repositoryId) {
      store.action('_getCurrency', {repositoryId});
    }
  };
 
  // Display a panel with:
  // * a select element with a placeholder and all available currencies
  // * a panel with information about the selected currency
  return (
    <Styled id="CurrencySelector" css={css}>
      <div className="CurrencySelector">
        {currencies && (
          <div>
            <span className="CurrencySelector__Label">{labelCurrencies}</span>
 
            <select
              value={selectedCurrency && selectedCurrency.repositoryId}
              onChange={onCurrencyChange}
              onBlur={onCurrencyChange}
            >
              <option value="">{labelSelectACurrency}</option>
 
              {currencies.map(currency => (
                <option key={currency.repositoryId} value={currency.repositoryId}>
                  {currency.displayName}
                </option>
              ))}
            </select>
          </div>
        )}
 
        {selectedCurrency && (
          <div className="CurrencySelector__SelectedCurrencyInfo">
            {labelSelectedCurrency} {selectedCurrency.displayName} ({selectedCurrency.currencyCode})
          </div>
        )}
      </div>
    </Styled>
  );
};
 
/**
 * Wrap the component with a "connect" object that supplies the state's
 * currency info as props and redisplays the component when any of those
 * props change.
 */
export default connect(getCurrencyInfo)(CurrencySelector);

The select attribute has an onChange handler, and a function that is defined named onCurrencyChange. The value={currency.repositoryId} uses the ID of the currency as the value of the option. If the ID is defined, the code calls an action, which allows the widget to react to changes made in the currency list.

Widgets share detailed information using context. For example, the StoreContext is a store object method used to invoke actions. The store object has an action method that uses the action name and parameters to invoke actions on the store. Each action should have a corresponding saga or reducer to update the store with the new state.

Context provides a framework for component communication. The useContext React hook allows actions to read and access default context to the widget. Use the useContext hook to obtain the context of an application. There are several context that can be used within an application. The contexts used by each widget indicates what methods and utilities will be available. Context invokes actions and returns action methods.

To reference the action in the example, use the React useContext hook. The storeContext allows you to get the value of a global variable, or a reference to the applications state. Once you have referenced the action, use the action function to dispatch actions. The action this example dispatches is the _getCurrency action. This example passes in the payload, which is the repository ID of the currency requested. This is described in the /plugin/components/currency-selector/index.js file. Note that this is a portion of the code example referenced above:
import React, {useContext} from 'react';
 import {StoreContext} from '@oracle-cx-commerce/react-ui/contexts';
...
  // Make sure we have the latest currency list during client-side rendering.
  const store = useContext(StoreContext);
  useListCurrenciesFetcher(store);
 
  // Invoked when the user selects a currency from the
  // select element. Invokes the '_getCurrency' action to
  // update the selected currency with info from the server.
  const onCurrencyChange = event => {
    const repositoryId = event.target.value;
    if (repositoryId) {
      store.action('_getCurrency', {repositoryId});
    }
  };
When this action is invoked, the getCurrency endpoint is called with the given ID and a part of the state identified as myRepository.currencyInfo.selectedCurrency is updated. Because the code is listening for changes in CurrencyInfo, it re-renders when there are changes. The following example uses a <div> that is rendered when there is a selected currency. This <div> contains a source string, a displayName and a currencyCode. This is added to the /plugin/components/currency-selector/index.js file. Note that this is a portion of the code example referenced above:

         {selectedCurrency && (
           <div className="CurrencySelector__SelectedCurrencyInfo">
             {labelSelectedCurrency} {selectedCurrency.displayName}
                ({selectedCurrency.currencyCode})
           </div>
         )}

When you access store data on your UI components, use selectors and pass them using the connect method. It is important that you use the correct selector method to fetch the precise information required for rendering the UI component. There are a number of default selectors that enable you to retrieve store state, however, if you cannot find a selector that meets your needs, you will have to create a custom selector. You can also use the useSelector hook to obtain part of the state information.

When you use the StoreContext hook to get the store object, you must us an action method that uses the action's name and parameters to invoke actions on the Redux store. Each action must have a corresponding saga or reducer that updates the store with the new state. Note that the action dispatch call should happen only when using the useEffect hook. It is best not to invoke any action calls in a React function component render method or useMemo hook.