Skip to main content

Using Redux Store

Overview

In the previous tutorial you created the SignOnCompletionPrompt React component using the wizard and wired it to the SignOnComplete extension process. In this tutorial we will work with that same component to understand how it connects to the Redux store, how to read data from it, and how to send events back to the process.

What You'll Learn

  • To be able to view the redux store
  • To be able to extract data from the redux store and display the data
  • To be able to send events to the process

Pre-requisites

  1. You have completed the Create a New React Prompt tutorial and have the SignOnCompletionPrompt component in your extension project.
  2. The Web POS Tomcat server and the Extension Dev Server are both configured and ready to start (see React Extension with Web POS).
  3. To have an understanding of React and Redux.

Exercises

View the SignOnCompletionPrompt in the Browser

Start the Web POS Tomcat server and the Extension Dev Server as you did in the previous tutorial.

Once both are running, open the Web POS in the browser and complete the sign-on flow. After sign-on completes, the SignOnCompletionPrompt should appear displaying the Location ID and Location Name.


Understanding the Redux Connection

Open the SignOnCompletionPrompt component file in your extension project. Scroll to the bottom of the file. You will see:

export default connect(
mapStateToProps,
mapDispatchToProps
)(SignOnCompletionPrompt);

Enactor provides the methods defaultMapStateToProps and defaultMapDispatchToProps to help with the binding of the props (data) and the redux actions.

In our component, these are used inside mapStateToProps and mapDispatchToProps — the two functions passed to connect. mapStateToProps spreads defaultMapStateToProps to pull standard prompt data out of the store, and mapDispatchToProps spreads defaultMapDispatchToProps to provide the eventHandlers (including sendEvent) as props.

The connect function from react-redux is what binds the Redux store to your component. It wraps SignOnCompletionPrompt and injects store data and dispatch functions as props.

There are two parts to this binding:

mapStateToProps — reads data out of the store and passes it into the component as props:

const mapStateToProps = (state, ownProps) => {
const { promptUrl } = getPageState(state, ownProps);
const inputState = getInputsForPromptUrl(state, promptUrl);

return {
...defaultMapStateToProps(state, ownProps),
inputState
};
};

defaultMapStateToProps from @enactor/react-base-components provides the standard set of props that every prompt needs: promptData, processId, promptUrl, promptInstanceId, promptTimeout, and locale. The inputState spread adds form input state on top of that.

mapDispatchToProps — creates functions that dispatch Redux actions and passes them into the component as props:

const mapDispatchToProps = (dispatch, ownProps) => {
return {
...defaultMapDispatchToProps(dispatch, ownProps),
setInputValue: (promptUrl, inputName, value) => { ... },
inputStateCleanup: promptUrl => { ... }
}
}

defaultMapDispatchToProps provides the eventHandlers object, which contains sendEvent — the function used to fire events back to the process.


Explore the Redux Store in Browser DevTools

Open your browser's DevTools while the SignOnCompletionPrompt is displayed.

Navigate to the Redux tab using inspect(provided by the Redux DevTools browser extension).

DevTools

In the state tree, navigate to:

enactorBridge → Prompts → pagesMap → <PageID> → pageResponse

Inside pageResponse you will find the following fields:

FieldDescription
promptDataThe data available to this prompt at runtime. For SignOnCompletionPrompt this contains locationId and locationName — the values mapped from the ILocation input in the process.
processIdThe ID of the running process, e.g. SignOnComplete_1.0
promptUrlThe URL of the current prompt, e.g. SignOn/Complete
pageUrlThe URL of the React POS application
promptInstanceIdA unique ID for this prompt instance — changes on each new prompt load
promptTimeoutSeconds before the prompt auto-times out. 0 means no timeout.
localeThe locale of the running POS server

Redux Dev Tools

The locationId and locationName values you see here are the same values that flow into the component via props.promptData. This is the bridge between the process and the React UI.


Inspect Props at Runtime Using the Console

The generated component already has two console.log calls near the bottom of the component function:

console.log(locationId);
console.log(locationName);

To see the full set of props available to the component, add the following two lines at the top of the SignOnCompletionPrompt function body:

const SignOnCompletionPrompt = props => {
console.log("*** props ***");
console.log(props);
// ... rest of the component

Save the file and wait for the dev server to rebuild. Reload the browser and complete sign-on again to trigger the prompt.

Open the browser's Console tab in DevTools and search for *** props ***.

Expand the logged object to explore everything available to the component. You will recognise promptData, promptUrl, processId, and eventHandlers — all injected by the connect wrapper you examined in the previous section.

Props

info

Every prompt in the system has access to this same standard set of props via defaultMapStateToProps and defaultMapDispatchToProps. Understanding what is available here is key to building any React prompt.


Understanding How promptData Is Populated

Look at the top of the component function where the prompt data is destructured:

const { promptData, promptUrl, inputState, setInputValue } = props;

const locationId = promptData.locationId;
const locationName = promptData.locationName;

These values — locationId and locationName — come directly from the State-Process Mapping you configured in the SignOnComplete_1.0.xml process in the previous tutorial. The process mapped:

  • Location → locationId using location.locationId
  • Location → locationName using location.description

When the Prompt State in the process fires, these mapped values are serialised and sent to the React component via the Redux store as promptData. This is the data pipeline: Process inputs → State mappings → Redux store → promptData → component props.


Understanding How Events Are Sent

Scroll to the handleOKPressed function in the component:

const handleOKPressed = () => {
const {
eventHandlers: { sendEvent }
} = props;
if (
(Object.values(formStateValidity) || []).some(value => value === false)
) {
return;
}
sendEvent("OKPressed", getInput());
};

sendEvent is provided by defaultMapDispatchToProps via eventHandlers. It takes two arguments:

  1. The event name — must match an event configured on the Prompt State in the process (in this case OKPressed)
  2. An optional data object — any output values to pass back to the process

The getInput() call returns the current form input values. Since this prompt has no outputs, it returns an empty object {}.

The button that calls this handler is rendered at the bottom of the component:

<button
className="btn btn-grey medium"
onClick={handleOKPressed}
style={{ marginTop: "20px", marginRight: "10px" }}>
OKPressed
</button>

Extension Exercise

Add a CancelPressed Event

The SignOnComplete_1.0.xml process currently only handles OKPressed. As an extension exercise:

  1. Open SignOnComplete_1.0.xml and add a CancelPressed event to the Prompt State. Cancel Pressed Event

  2. Link it to a new End Process with Failed Outcome.

New End Process

  1. In the SignOnCompletionPrompt component, add a second button that fires the CancelPressed event:
<button
className="btn btn-grey medium"
onClick={() => props.eventHandlers.sendEvent("CancelPressed")}
style={{ marginTop: "20px" }}>
CancelPressed
</button>

Cancel Button

  1. Save the file and wait for the dev server to rebuild. Reload the browser and sign on to trigger the prompt.

Enable process tracing in Eclipse as shown below, then sign on again so the prompt appears.

Process Trace

With tracing active, click each button in turn and observe the process trace in Eclipse. Clicking OKPressed should advance the process along the success path, while clicking CancelPressed should take the process along the failure path. This demonstrates how the event name passed to sendEvent in the React component directly determines which branch the process follows.