Using React in a NetSuite Suitelet

I’m interested in reusable client-side components in NetSuite. React seems to be a very popular non-framework (It’s a JavaScript library… Everybody knows that). I put together this example for myself and thought I’d share it. 

In this exercise, I’m going to write in SuiteScript 2.0. I need the practice! I’ll split up the code into separate files that isolate functionality.

Let’s pretend I’m going to build a library of React components and include them in Suitelets. In my example, I’m serving a component called PartFinder. It doesn’t actually do anything, but imagine it calling the SuiteCommerce Advanced SOLR search engine to find parts based on SCA’s facets (attributes like height, width, weight, vendor, color, price, etc). If you skip ahead to the second to the last image, you’ll see what the component actually looks like.

Imagine being able to drop this component into any Suitelet or add it to existing NetSuite pages as needed with just a couple of lines of code.

Here’s my schematic.

MovingParts

There are 4 files that make up this example. The logic_react_other(s).js represent other React components.

  1. logic_suitelet_react.js – This creates a page, adds a form. In the form it adds an inline HTML element which consists of several parts:
    1. The included react and babel libraries required by React.
    2. A div element with an id of dynHTML. This is where the React component is rendered.
    3. All the code to replace dynHTML with the server-built HTML & JavaScript to show a component called PartFinder.

logic_suitelet_react.js

2. A non-AMD compliant library that serves React components along with supporting HTML & JavaScript. It’s the one-stop-shop for React.

logic_react_lib.js

3. A config file which is required for non-AMD compliant libraries.

ReactLibConfig

4. A static file which is the React PartFinder component. This could live in logic_react_lib.js, but I chose to split it out. Nice and tidy!

logic_react_PartFinder

This is what the component looks like in the rendered Suitelet.

RenderedSuitelet

This is the actual HTML and JavaScript you see when you inspect the page at the client.

ReactDOM

And here is my example code in a format you can cut and paste into your IDE. Use this at your own peril (my attorney made me say that!).

/**
*@NApiVersion 2.x
*@NScriptType Suitelet
*@NAmdConfig ./ReactLibConfig.json
*/
define([‘N/ui/serverWidget’, ‘N/file’, ‘react_lib’],
    function (serverWidget, file, react_lib) {
        function onRequest(context) {
            if (context.request.method === ‘GET’) {
                // Add a form
                var form = serverWidget.createForm({
                    title: ‘React Suitelet Demo’
                });
                // Add an inline HTML field
                var field = form.addField({
                    id: ‘custom_inline’,
                    type: serverWidget.FieldType.INLINEHTML,
                    label: ‘Inline’
                });
                // Add the html
                field.defaultValue = react_lib.getReactIncludes() + 
                    ‘<div id=”dynHTML” />’ +
                    react_lib.getComponentScript(‘PartFinder’, ‘dynHTML’, file);
                context.response.writePage(form);
            }
        }
        return {
            onRequest: onRequest
        };
    }
);
/**
* @NApiVersion 2.0
* @NModuleScope public
*/
var logic_react_lib = {
    getReactIncludes: function() {
        return [
                ”,
                ”,
                ”,
                ”,
                ”,
            ].join(“\n”);
    }
    ,
    getComponentScript: function(componentName, tagName, file) {
        switch (componentName) {
            case ‘PartFinder’:
                return [
                    ”,
                    ”,
                    this.PartFinder(file),
                    ‘   ReactDOM.render(‘,
                    ‘      ,’,
                    ‘      document.getElementById(“{tagName}”)’.replace(‘{tagName}’, tagName),
                    ‘   );’,
                    ”,
                    ”].join(“\n”);
            break;
        }
    }
    ,
    PartFinder: function(file) {
        var fileObj =
            file.load({
                id: ‘SuiteScripts/Logic/logic_react_PartFinder.js’
            });
        return fileObj.getContents();
    }
}
{
    “paths”: {
        “react_lib”: “SuiteScripts/Logic/logic_react_lib”
    },
    “shim”: {
        “react_lib”: {
            “exports”: “logic_react_lib”
        }
    }
}
/*
    This is all client side React Code in ES6.
    It is delivered as-is to the browser
*/
function PartFinder(props) {
    const [partname, setPartname] = React.useState();
    const [vendor, setVendor] = React.useState();
    const handleSubmit = event => {
        alert(partname + ‘ – ‘ + vendor);
        event.preventDefault();
    };
    return (
        <form onSubmit={handleSubmit}>
            Item Name:<br />
            <input type=”text”
                value={partname}
                onChange={(e) => setPartname(e.target.value)}
            /><br />
            <br />
            Vendor Name:<br />
            <input type=”text”
                value={vendor}
                onChange={(e) => setVendor(e.target.value)}
            /><br />
            <br />
            <button>Submit</button>
        </form>
    );
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s