Create a React component
Describes how to use the JavaScript framework React in the Optimizely Content Management System (CMS) user interface. Most concepts apply to other JavaScript frameworks.
Optimizely Content Management System (CMS) supports using JavaScript frameworks in the user interface to build components used by editors in the on-page edit view.
Add components to different parts of the user interface. This example describes how to create a custom edit view.
Register the view server-side
Register a ViewConfiguration class on the server side and point to the JavaScript file to load. The file is your bundled React view. The following code registers the view:
[ServiceConfiguration(typeof (ViewConfiguration))]
public class MyView: ViewConfiguration<IContentData> {
public MyView() {
Key = "my-view";
Name = "React View";
ControllerType = "alloy/components/ReactGadget";
IconClass = "epi-iconStar";
SortOrder = 100;
}
}In edit view, an extra view (Custom view) is listed in the view switcher.
Create the entry point
A typical React application has an entry point called index.js that calls ReactDOM.render (see ReactDOM Render section). Because the view runs inside a Dojo application, the entry point must act as a widget that calls ReactDOM.render. The following code creates this entry point:
index.js
import React from "react";
import ReactDOM from "react-dom";
import declare from "dojo/_base/declare";
import WidgetBase from "dijit/_WidgetBase";
import MyComponent from "./MyComponent";
export default declare([WidgetBase], {
postCreate: function() {
ReactDOM.render( < MyComponent / > , this.domNode);
},
destroy: function() {
ReactDOM.unmountComponentAtNode(this.domNode);
}
});This creates a widget that renders the React component to its DOM node. It also unmounts the component when the view is destroyed.
Use this code as a boilerplate and replace MyComponent with your React component.
Build the bundle
Bundle your MyComponent into a single file (the one your view configuration points to) to display it in the user interface. Use bundlers like webpack or rollup. The following examples demonstrate both methods.
Because CMS uses AMD for module loading, the bundle must also be AMD formatted. The build tools handle this with a single configuration line.
In the entry point code from the previous example, there are imports for Dojo and Dijit. These exist inside the CMS application and should not be bundled, so mark them as external. This requires a few lines of configuration.
The entry point for your bundle is the index.js file from the previous example. The output file should be the path to the folder for your JavaScript file configured in your module.config, plus the relative path to the file configured in the view configuration. Change the paths in the following examples to suit your needs.
webpack.config.js
const path = require("path");
module.exports = {
entry: path.resolve(__dirname, "src/index.js"),
output: {
filename: "ReactGadget.js",
libraryTarget: "amd",
libraryExport: "default",
path: path.resolve(__dirname, "ClientResources/Scripts/components/")
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}]
},
externals: [
"dojo/_base/declare",
"dijit/_WidgetBase"
]
};The key parts of this configuration are the settings for libraryTarget, libraryExport, and externals.
For webpack, set libraryExport to return the default export from the entry point rather than an object containing the exports.
rollup.config.js
import babel from "rollup-plugin-babel";
import commonjs from "rollup-plugin-commonjs";
import replace from "rollup-plugin-replace";
import resolve from "rollup-plugin-node-resolve";
export default {
input: "src/index.js",
output: {
file: "ClientResources/Scripts/components/ReactGadget.js",
format: "amd"
},
plugins: [
babel({
exclude: "node_modules/**"
}),
commonjs(),
replace({
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV)
}),
resolve()
],
external: [
"dojo/_base/declare",
"dijit/_WidgetBase"
]
};The key parts of this configuration are the settings for format and external.
Access CMS features from the React component
After loading your React component in the user interface, use CMS components from within it. For example, let the user select a page using the content selector.
Events are automatically connected from the props to the widget based on the naming convention onEventName. Settings for the widget are only passed during construction. Setting changes are not propagated after mount.
The following example shows usage with a content selector:
import React, { Component } from "react";
import DojoWidget from "./DojoWidget";
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
value: null
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(value) {
this.setState({ value });
}
render() {
const { value } = this.state;
const label = value ? <div>ContentLink: {value}</div> : null;
return (
<div>
<DojoWidget type="epi-cms/widget/ContentSelector" settings={{ repositoryKey: "pages" }} onChange={this.handleChange} />
{label}
</div>
);
}
}
export default MyComponent;The @episerver/amd-loader-proxy mentioned earlier (see also @episerver/amd-loader-proxy) dynamically requires AMD modules from CMS in your JavaScript application. This is framework agnostic, so use it with any JavaScript framework.
Updated 17 days ago
