Creating Lightning Components with React

The Lightning Component Framework is a great UI framework for building modern components and applications on the Salesforce platform. If you are already invested in other UI frameworks, like React or Angular, you can also integrate components built with these frameworks inside Lightning Components.

In this post, I’ll share a project that demonstrates how to build a Lightning Component with React, or in other words, how to host a React Component inside a Lightning Component. The example used in this project is a simple Contact Search component fully implemented in React.

The React Component is loaded in your Salesforce Org as a Static Resource, and leverages the Lightning Component’s standard data access infrastructure.

There are two things a React component needs in order to function properly inside a Lightning Component:

  • A reference to the DOM element that serves as the container for the React component
  • A reference to a data service that the React component can call when it needs data

These two parameters are provided to the React Component in the Lightning Component’s reactInit() function that is executed when the Static Resource has been loaded (see the ReactSearch controller implementation below). The data service is just an object containing functions the React component can call when it needs data. These functions use the traditional Lightning Component syntax to access methods in the component’s Apex controller. The approach presented in this project also allows you to test your React components outside Salesforce using a mock data service.

Step 1: Building and Running the React Component Locally

  1. Clone the lightning-react repository which includes the React component and the associated build scripts
  2. Open a command prompt and navigate (cd) to the lightning-react directory
  3. Install the project dependencies:
    npm install
    
  4. Build the project:
    npm run webpack
    
    This project uses Babel to transpile ES6 and React’s JSX, and Webpack to implement modules. The transpiled file is available in the build directory.
  5. Test locally. The project includes a mock.js file that simulates a Lightning Component so that you can test your React code locally before deploying it in your Salesforce org. To test the app locally, open index.html in your browser and type a few characters in the search box.

Step 2: Hosting the React Component in a Lightning Component

  1. In the Developer Console, create an Apex Class named ContactController implemented as follows:
    public with sharing class ContactController {
    
        @AuraEnabled
        public static List<Contact> findAll() {
            return [SELECT Id, Name from Contact limit 20];
        }
    
        @AuraEnabled
        public static List<Contact> findByName(String name) {
            String key = '%' + name + '%';
            return [SELECT Id, Name FROM Contact WHERE Name LIKE :key LIMIT 20];
        }
    }
    

    In a production environment, you should add code to the controller’s methods to enforce CRUD and FLS. More information here.
  2. Create a Static Resource named ReactSearch. Upload the search.bundle.js file available in the build directory.
  3. Install the Lightning Design System: On the downloads page, click v0.12.2 unmanaged package, then click the Install button. This will install the Lightning Design System as a static resource in your org.
    You could also use your own styles, but using the Lightning Design System will ensure UI consistency.
  4. In the Developer Console, create a new Lightning Component (File > New > Lightning Component) named ReactSearch implemented as follows:
    <aura:component controller="ContactController">
        
        <ltng:require scripts="/resource/ReactSearch"
                      styles="/resource/SLDS0122/assets/styles/salesforce-lightning-design-system-ltng.css"
                      afterScriptsLoaded="{!c.reactInit}"/>
        
        <div aura:id="container"/>
        
    </aura:component>
    
  5. Click CONTROLLER (upper right corner) and implement the component’s controller as follows:
    ({
        reactInit : function(component, event, helper) {
            var dataService = {
                findAll : $A.getCallback(function(callback) {
                    var action = component.get("c.findAll");
                    action.setCallback(this, function(a) {
                        var contacts = a.getReturnValue();
                        callback(contacts);
                    });
                    $A.enqueueAction(action, false);
                }),
                findByName : $A.getCallback(function(name, callback) {
                    var action = component.get("c.findByName");
                    action.setParams({name: name});
                    action.setCallback(this, function(a) {
                        var contacts = a.getReturnValue();
                        callback(contacts);
                    });
                    $A.enqueueAction(action, false);
                })
            }
            
            var container = component.find("container").getElement();
    
            reactSearch.init(container, dataService);
            
        }
    })
    
    

    The key here is to wrap the data service’s functions in $A.getCallback() which returns a callback that is safe to invoke from outside the Lightning Component lifecycle.
  6. Create a new Lightning Application (File > New > Lightning Component) named ReactSearchApp implemented as follows:
    <aura:application >
        
        <c:ReactSearch />
        
    </aura:application>
    
    
  7. Click Preview (upper right corner) to run the app. Enter a few characters in the search box to search contacts by name.

Disclaimer

This project is meant as a technical proof of concept. It is not implied that the solution presented in this article would currently pass AppExchange security review. At the time of this writing, the security requirements checklist states that: “Any Lightning package that uses Angular or React or other third party DOM-based templating frameworks will automatically fail the security review until such time as we provide custom lightning components to properly encapsulate these frameworks. This is to avoid template injection attacks resulting from double interpolation. In order to use another framework as part of a package that uses Lightning, please use an iframe or Visualforce container until approved Lightning containers are published.”

  • Jason

    Hi Chris,

    Do you know if we can use React in Lightning Components that are intended to be included in managed package?

    I had read that any Lightning Component that used React (or any other DOM manipulation framework) would fail security review due to “template injection attacks resulting from double interpolation”. Is the lightning-react repo you linked to considered an approved Lightning container for React?

    https://developer.salesforce.com/page/Requirements_Checklist

    -Jason

    • Christophe Coenraets

      Hi Jason. Thanks for the question. I just added a disclaimer at the bottom of the article. This approach would currently not pass AppExchange security review for the reason mentioned above … “until approved Lightning containers are published”.

  • Would this pass for an UnManaged package?

  • Robert Sussland

    You are doing DOM modification in the controller, instead of in a renderer. As a result, the lightning component doesn’t know how to render itself, and this creates problems for it when the framework unrenders and then re-renders the component. In those situations, the framework will call a render event (which does nothing) but wont reload the script (which is already in the DOM). The old container element will be put in the trash and a new container element will be generated, but react will still try to work with the old container element, since it hasn’t been told to switch to a new element. The whole react app dissapears.

    For example, suppose your app looked like this:

    Here’s some text!

    Here’s a react component

    with controller.js:

    ({
    toggle : function(component, event, helper) {
    component.get(‘v.display’) ? component.set(‘v.display’, false): component.set(‘v.display’, true);

    }
    })

    Now, toggle three times. The react app dissapears. If you had coded this to contract, then it wouldn’t disappear.

    These types of issues are really subtle — you can test your own app as much as you want but you wont know that it fulfills the contract of a component until you know that it is following all the requirements in the developer guide.

    Everything attempt to do DOM modification in the controller so far has been like your example — works really well when tested by the developer and starts to break when they are unrendered, or some event is sent to them, or they are put in a repeat tag, or switched around in tabs, etc. Then things start to break. Stuff like this has real repercussions for the overall stability lightning component consumers.

    Lightning is really magic, because it allows different dev teams who don’t test together to have their code running together simultaneously. In order for that happen, everyone has to code to contracts rather than just code to get their own part working.

    Having said that, you may not care about complying with contracts if you own the entire page. For example, everything is being rendered in a visualforce page with lightning out and you fully control the context in which the component is rendered. Or you are doing development in your own org. In that case, you can strategically break some rules provided you have a deep understanding of the framework and solid testing. But please don’t mistake that for a code-to-contract component that is fully “pluggable” — e.g. can be grabbed by another developer and used as they see fit without knowing the source code.

  • Robert Sussland

    Sorry, looks like your comments aren’t encoding less than signs. Here is a gist of the App that higlights the issues. Press toggle 3 times

    https://gist.github.com/rsussland/135bc5bde14674b34029

  • ess than signs.

  • Cory Cowgill

    Can someone speak to when MV* frameworks will be supported? Is this on the roadmap? This is a major blocker to adoption. My engineers are not going to rewrite our SPA’s that live in VF Managed Packages today that use ReactJS into Lightning specific components.

  • Richard Cook

    What is the “danger” of doing this now if we don’t plan on publishing in AppExchange and we’re behind our Salesforce logins?

  • Located an hour from city of Gurgaon, Sohna street has constantly drawn a considerable measure of consideration from individuals living in Gurgaon because of its pleasant settings, hot springs and the way that it is really one of the real tourism destinations inside the locale. Interest has expanded for new activities in Gurgaon, Sohna street, because of property engineers like Unitech setting up a progression of restrictive groups and mid to top of the line land ventures in the zone. Get accurate information on Residential Real estate in Gurgaon. Find and compare Residential Projects and Property in Gurgaon
    Real Estate property in Gurgaon

css.php