Yegor Shytikov
6 min readDec 4, 2019

Using React library with Magento 2 and Magento 1

Right, Magento 1 Open Source (CE) will be alive after announced EOL and works better than Magento 2 and will receive a second life and Open Source freedom. This approach will bee pull requested to the core of https://github.com/OpenMage/magento-lts repo.

Check the performance overview:

The article was made by analyzing react Magento React GitHub repo:

https://github.com/Genaker/reactmagento2

What is React

First of all, and to avoid a common myth, React is not a Javascript Framework like Angular, it is just a view library from the Facebook team (best world software developers working for this company) that provides a few function hooks to render HTML. It sounds quite simple, but in fact is a bit more complex, in the end, React is JS library to build user interfaces, that approaches a concept of reusable components (UI Components) and solve a historical issue with the slowness of the DOM by replacing it with a Virtual DOM structure!

Unlike older JavaScript solutions, which involved manually triggering changes on the page, React “knows” when the UI needs to be updated and re-rendered on the page when the states of the components change. The main idea that differentiates React from other libraries or frameworks (e.g. AngularJS, Knockout) is the use of a “virtual DOM”, which enhances performance by reducing the number of changes happening on the DOM.

Using it inside Magento2 or M1

I believe that one of the fundamental strengths of Magento platform is the flexibility of modeling and storing structures of Product Data (mainly because of EAV), and one of the weaknesses is on the way we consume and display those structures to the end-user, mostly when the required user interactions are complex. The combination of Knockout JS templates with jQuery is not good enough when the complexity increases, and often, we end with dozens of tweaks that are not good for the performance and code manageability. So why not forget it and make use of a modern library that is component-based and provides us all modern mechanisms to build rich user experiences.

Why Magento can’t have good UI?

JS Teamworks popularity

Simple scenarios to use React inside Magento:

For this post, I’m just concerned about having one or more React components rendered in a Mgento page. I’m not interested in having a single React page application or having a full headless solution (PWA or Heedless Theme like VueStorefrony). I just want to show the possibility to solve the complexity of some page components with React, let’s call it a High-Performance Hybrid React integration with Magento. It uses inline JSON directly from the page. The same approach used in Magento 2 Backend and Frontend checkout, color swatches by default but with legacy Knockout JS/jQuery library. Also can use Ajax HTTP call to fetch data (not the best solution because Magento API is slow and will increase the load on your Back-end server).

In way to do that, we have a few challenges to solve:

1. Avoid including the React library on each React component

There are many ways to start a React application, by using some boilerplates or tools like the Facebook create-react-app (https://github.com/facebook/create-react-app). Using create-react-app will help us since it removes some tricky configuration aspects and simplifies a lot the development phase.

npm start

To build our app we just need to run webPack build and it will create in the build folder the transpiled JS files with all dependencies including the react and react-dom js files, the aggregated CSS files, and any other referenced assets.

Web Puck compiles everything automatically into React/React/view/base/web/js/index_bundle.js and deploys to pub/static without running static:deploy ssh command. LiveReload Plugin will reload magento 2 pages automatically (not recommended solution by React Community. F5 more reliable solution). What you need just disable the Cache of your browser during development. Also, You can disable caching for a single react bundle file via Nginx config.

See all config file: (https://github.com/Genaker/reactmagento2/blob/master/React/React/webpack.config.js)

That is ok if we are doing a single react page, but what happens if we want to render multiple react apps on the same page, we are including redundant code as the react js files are included in the build.

To avoid that we can do an eject and manipulate the create react app configurations and scripts, or use the react-app-rewired module (https://github.com/timarney/react-app-rewired) as it provides the ability to override webpack configs without the need of ejecting:

yarn add --dev react-app-rewired

After we have the module installed we can create a config-overrides.js file in the root directory and define as external the react and react-dom libs:

/* config-overrides.js */
module.exports = function override(config, env) {
// Use external version of React
config.externals = {
"react": "React",
"react-dom": "ReactDOM"
};
return config;
}

2. Load the React component in Magento Page

The create-react-app will produce a bundle.js, we just need to expose them to Magento in request config JS (React/React/view/base/requirejs-config.js) :

var config = {                          
map: {
'*': { 'react-app': 'React_React/js/index_bundle', }
},
};

See this file: (https://github.com/Genaker/reactmagento2/blob/master/React/React/view/base/requirejs-config.js)

For Magento 1 it is even more simple just add js fit layout.xml

<?xml version="1.0"?>
<layout version="0.1.0">
<default>
<reference name="head">
<action method="addJs">
<script>react/index_bundle.js</script>
</action>
</reference>
</default>
</layout>

You can also use the same approach for Magento 2 without any require JS, webPack manage all js dependencies now. Why not?

And attach our library to a template file that contains a div that matches the React code.

3. Provide a mechanism to pass Magento information as props to the react components

The mechanism in React to pass information between components is based on the concept of Props, so for instance, if we have a Message component that needs to render a text message in green or red (info or alert) we can pass him the text message (string) and the type (string) using props like below:

<PopUp text="Black Friday sale" type="alert" />
<PopUp text="Magento 2 UI sucks" type="info" />

So how we can pass information from Magento to a React component?

I figured out two different ways, the first one is based on data attributes that are present in the div element that React will handle, e.g.:

<div id="react-message-component" data-type="info" data-text="Info message"></div>

and then on the React component we just need to handle the data attributes:

import React from 'react';
import ReactDOM from 'react-dom';
import PopUp from './PopUP';
var root = document.getElementById('react-message-component');ReactDOM.render(<PopUp {...(root.dataset) } />, root);

The above approach can be a bit problematic if we have complex attributes, and therefore believe the next approach is a bit better. We can set our props in a document object array and since it is defined globally we can access it from React. So when rendering our templet.phtml in Magento we can attach the settings:

<script> 
document.reactMagento = {
"message": "Goodby Knockout!",
"element": "magento-div",
"type": "alert",
"json-data": <?php echo $json; ?>, document.rect_translate = {
description: "<?=__('React Component')?>", view_more: "<?=__('View More')?>", add_to_cart: "<?=__('Added to cart')?>", }
}
</script>

and on React we can access to the global reactMagento as below:

import React from 'react';
import ReactDOM from 'react-dom';
import Message from './Message';
const popUp = document.reactMagento || {};
ReactDOM.render(
<PopUP
text={popUp.message}
type={popUp.type}
/>,
document.getElementById(popUp.element);
);

4. Have a consistent mechanism to map Magento components to React components

In our hybrid approach, we are using React for dealing with the UX complexities, but still relying on Magento for handling the contents. We need to have also the Layout-Block concept on Magento, but instead of dealing with the presentation (template.phtml) it will deal only with the data organization of content (Block).

  1. There is main entry point “index.php" which will load whole application and start it. Return Data from FPC if exist.
  2. Base on the requested URL appropriate controller will be called.
  3. Controller defines the pages and load the layout files for those pages.
  4. Layout files tells the controllers which block files to use.
  5. Block files collect the data from models and and pass it to templates files as json .
  6. Templates files receive data and render react component js file! .

Example Of Magento React Hybrid interaction

Magento Hybrid React interaction

I’m aware that above is a very simple example that doesn’t expose the React capabilities but at least we can see how the interaction between Magento and React can happen.

Yegor Shytikov
Yegor Shytikov

Written by Yegor Shytikov

True Stories about Magento 2. Melting down metal server infrastructure into cloud solutions.

No responses yet