Hello world node.js app which shows how Interaction Studio can work with a React based website for both personalisation and listening
Page template uses EJS template engine. Index page is located here: ./views/pages/index.ejs
Express is used for the MVC pattern. routes.js and controller.js handle HTTP requests and return the page HTML.
Make sure to set the following environment variables:
- IS_API_CREDENTIALS
- IS_AUTHEVENT_HOSTNAME
- IS_AUTHEVENT_PATH
- IS_BEACON_URL
The React components are located in the /public/js folder
The Interaction Studio sitemap and templates used are located in the /interaction-studio folder. You'll need to setup these in Interaction Studio with corresponding web campaigns and a server side campaign based on the templates.
The app requires node.js installed. Use the following commands to initialise and start the app:
- npm init
- node app.js Then navigate to localhost:3000 in your browser. See screenshot.PNG for an example.
Notes:
- All code in this repository is for educational purposes only
There are 4 patterns for Interaction Studio campaigns to personalise content inside React components on a website.
- IS replaces placeholder React component content
- IS updates React component state directly
- IS updates store which React component subscribes to
- Server side rendered React component which uses Event API and server side campaigns
HTML contains a div <div id="banner1"></div>
which is configured as a content zone in the sitemap. The JavaScript file banner1-placeholder.js attaches a placeholder React component to the element.
The React component shouldComponentUpdate() returns false which allows IS to manipulate the DOM. The IS web template replaces the React component HTML with campaign generated HTML.
HTML contains a div <div id="banner2"></div>
. The JavaScript file banner-with-cta1.js attaches a React component to the element. This element contains some default state data for ctaUrl, subheader, header, ctaText and imageURL which is used when rendering the React component.
The rendered React component is made available to window object via reference <Banner2SetState ref={Banner2SetState => {window.Banner2SetState = Banner2SetState}} />
.
The IS web template updates the state of the React component which makes it automatically re-render. Handlebars and CSS are not required in the template.
return Evergage.util.resolveWhenTrue.bind(() => {
if (Evergage.cashDom("#banner2 .banner").length > 0 ) {
Evergage.DisplayUtils.bind(buildBindId(context));
Banner2SetState.setState({
ctaUrl: context.ctaUrl,
subheader: context.subheader,
ctaText: context.ctaText,
imageURL: context.imageURL,
header: context.header,
experience : context.experience,
userGroup : context.userGroup,
campaign : context.campaign
});
return true;
}
});
HTML contains a div <div id="banner3"></div>
. The JavaScript file banner3-reduxStore.js creates a Redux store and a React component.
const myStore = Redux.createStore(myReducer);
The initial state of the React component comes from the Redux store getState() function.
/**
* Constructor
*/
constructor(props) {
super(props);
this.state = myStore.getState();
}
The IS web template dispatches an action to update the Redux store with new data. Handlebars and CSS are not required in the template.
myStore.dispatch({
type : 'BANNER_UPDATE',
payload : {
ctaUrl: context.ctaUrl,
subheader: context.subheader,
ctaText: context.ctaText,
imageURL: context.imageURL,
header: context.header,
experience : context.experience,
userGroup : context.userGroup,
campaign : context.campaign
}
});
The rendered React component is made available to window object via reference <Banner3ReduxStore ref={Banner3ReduxStore => {window.Banner3ReduxStore = Banner3ReduxStore}} />
.
The React component subscribes to any Redux store changes. Whenever the store changes, the state of the React component is updated which causes it to re-render.
myStore.subscribe(() => Banner3ReduxStore.setState(myStore.getState()));
The controller.js file handles incoming HTTP requests and returns the page HTML. When a request comes in, it calls the IS API to retrieve any server side campaigns. The HTTP request includes a 1 second timeout. If a campaign response is returned, a React component is rendered server side using the campaign data passed in as properties.
let props = {
ctaUrl: jsonResponse.campaignResponses[0].payload.ctaUrl,
subheader: jsonResponse.campaignResponses[0].payload.subheader,
ctaText: jsonResponse.campaignResponses[0].payload.ctaText,
imageURL: jsonResponse.campaignResponses[0].payload.imageURL,
header: jsonResponse.campaignResponses[0].payload.header
};
const html = ReactDOMServer.renderToString(React.createElement(Banner4Server, props));
The HTML of the React component is output directly into the EJS template e.g. <%- campaigns[0].html %>
Note that a separate API request is needed to send campaign stats (e.g. impressions, clicks etc...) for server side campaigns
The most elegant way to listen to UI events within a React component is to change the React component to send custom JS events which Interaction Studio can listen to.
For example, the ToggleBtn component sends a custom JavaScript event whenever the button is clicked
handleClick() {
this.setState(prevState => ({
isToggleOn : !prevState.isToggleOn,
clicks : prevState.clicks + 1
}));
document.dispatchEvent(new CustomEvent('toggle-btn-click'));
}
/**
* DOM rendering logic
*/
render() {
return (
<div className="toggle-btn">
<a onClick={this.handleClick} className="slds-button slds-button_neutral">{this.state.isToggleOn ? 'ON' : 'OFF'}</a>
<p>Clicks: {this.state.clicks}</p>
</div>
)
}
Then in the Interaction Studio sitemap code, an event listener catches the custom JavaScript event and then sends a "tracking" event to Interaction Studio as follows:
// Custom event listeners for React component UI events
document.addEventListener('toggle-btn-click', () => {
Evergage.sendEvent({
'action' : 'Toggle Btn Click'
});
});