Tag Archives: React

React.js and MobX: Escape the Redux trap

I have seen React in action for the first time in relatively complex legacy application. There were some attempts to develop new functions using React and, of course, Redux. Because everyone is using that combination. It is the clear, cool way. Hm…

notsure

I fell in love with React quickly but with Redux it was not so hot. Alex Dixon wrote great article about his problems with Redux and functional programming in JavaScript. TLDR:

  • You never know whether you have plain JS object or Immutable.js object under your hands.
  • If you are not using Immutable.js then you still should know whether object you have can be mutated or not.
  • In every file you have to manually import libraries like Immutable or Lodash.

I had those issues plus:

  • It was real pain to describe complex change you would like to perform on immutable state within store. Like add 6th item into array, remove 3 different keys from map, etc.
  • For doing even simple things you have to modify code in multiple files. One often do a hack instead of nice solution.
  • Problems with using multiple stores. I still had feeling that I should not store state of form in global store. Local data should be local, right?
  • Same store is used during navigation without page reload. It is hard to clean everything properly.
  • React-Redux library is doing incredible magic I was never able fully understand.
  • Using Promises just made thing worse.
  • I still had feeling that if I have to reorganize store structure I will got mad.

Then, out of blue sky, I have found MobX. And I realized that I found great React’s partner.

thinking

I can have multiple stores – one that holds application state (selected language, global formatting settings), second that holds form state and handles communication with server, third for caching currency conversions, etc. This stores are available through React context – therefore their presence is checked by React using contextTypes definition. You can freely move components in hierarchy as long as you assure that proper stores are in context.

I still have certain level of immutability because MobX checks that no change is done during processing previous change.

Adding functionality is deadly simple. You have two classes – component and store.

Because store is single purpose and is object of class, it is quite easy to determine what you can do with it. If there is method, try to call it. Compare that with searching for proper Redux action.

Despite I have never use truly functional programming language I highly utilize lambda expressions (Ruby, Java 8, JavaScript), enjoy passing function as parameter and since then my usage of class inheritance dropped by 90% ūüôā In Java I employ Immutables, Jooq and high percentage of methods I write are static ones. So I consider myself open minded in functional programming area. That hopefully gives me some credit to have strong feeling that combination of React and Redux is simply wrong. MobX and React, on the other hand, are just great combination.¬†At least for me ūüėČ

 

 

 

 

Advertisements

React.js components with embedded styles

You have probably already seen global CSS files with thousands of lines that may influence anything. Change is too dangerous so you just add new rules. To the point everything must be rewritten.

I love React’s ability¬†to build reusable components. Write once, put anywhere you like. This rule does not apply just¬†for JavaScript, it may apply for CSS too. Did you know that you can use¬†css loader¬†to autoprefix rules from CSS/SASS/LESS file? So every require of such file prepares class names that does not clash with anything else (like style__item___3dKqL).

That way you can prepare components that contains embedded styles that applies only for them. No complex CSS selectors are required – just use plain names:

embedcss

At the same time you can import application wide constants using SASS so you do not lose ability to set colors, sizes, … in single place.

Usage in code is simple:

code

(btw. to avoid join operation you can use classnames lib)

Right now I use following:

postcss.config.js

module.exports = {};

package.json

const path = require('path')
const webpack = require('webpack')

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'web-ui-bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.scss$/,
                use: [
                    {
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            modules: true   //!!!!!! This enables modules
                            localIdentName: '[name]_[local]__[hash:base64:15]'
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                        }
                    },
                    {
                        loader: 'sass-loader'
                    }
                ],
            },
            { 
                test: /\.js$/,
                use: 'babel-loader',
                exclude: /node_modules/
            }
        ]
    },
    devServer: {
        contentBase: './',
        hot: true
    },
    plugins: [
     new webpack.HotModuleReplacementPlugin()
    ]
};

webpack.config.js

{ 
    "name": "web-ui",
    "description": "",
    "version": "0.0.1",
    "dependencies": {
        "react": "15.6.1",
        "react-dom": "15.6.1"
    },
    "devDependencies": {
        "webpack": "3.5.2",
        "babel-core": "6.25.0",
        "babel-loader": "7.1.1",
        "babel-preset-es2015": "6.24.1",
        "babel-preset-react": "6.24.1",
        "webpack-dev-server": "2.7.1",
        "style-loader": "0.18.2",
        "css-loader": "0.28.4",
        "postcss-loader": "2.0.6",
        "sass-loader": "6.0.6",
        "node-sass": "4.5.3"
    },
    "scripts": {
        "build": "webpack",
        "devel": "webpack-dev-server --hot"
    },
    "browserslist": ["defaults", "not ie < 11"]
}

React.js: Build your components catalog

When you design large information system UI it is important to stay uniform. Nobody likes when pages varies in appearance or behavior. Typically it is necessary to write UI/UX design manual that describes allowed tools and techniques.

I was thinking about ways how to prepare list of UI components. So we can pick component when creating new functionality and avoid writing new. I was considering Confluence but it would need extra effort to keep list of components up to date.

Then I got it:¬†We can employ¬†React’s ability to prepare reusable components and easily compose catalog. Here is our:

catalogue

Catalog is embedded in application but visible only to developers. Every component¬†is shown in typical situation (to have concise list) and it may be expanded (Date component above) to be seen in various¬†configurations – error state, different input values, empty, …

We are using physics particles categories for components and each category has own section:

  • Quarks – simplest components that only use passed properties (Button, FormattedInput, …)
  • Atoms – components that call server API or are attached to forms or application state (ContextMenu, CurrencyInput)
  • Molecules – larger function blocks that contains application logic (UserForm, TasksList)
  • Pages – ok, this is not physics category ūüėČ

Each level uses components from upper levels. And each level is harder to instantiate outside its real usage. According to my experience it is quite feasible to have Quarks and Atoms in catalog. I believe that MobX is helping here but I have no long term experience with Redux. Molecules depends too much on API and application data so it would be hard to mock it.

You can also think about catalog as mild form of test. You are testing that:

  1. You can reuse component, there are no hidden dependencies
  2. There is no clash among components when used together
  3. All components basically works

 

Embedding React into legacy web pages

The product I am enthusiastically working on – Navigo3 – was historically written as combination of XSLT and JSP. Do you remember XSLT?

meme

Short time before I joined it it was decided that is should be remade in React.js. It was great decision but transition is not that easy.

Because Navigo3 is in production usage we have to transform from XSLT to React step by step. Some pages are that complex that it would be handy being able to combine XSLT and React on single page. Typically it is required¬†on pages that combine many types of information – dashboards. A few graphs, tables, list of tasks, …¬†It would be hard to rewrite all at glance. But rewrite each one is quite simple.

dashboard.png

At the same time we have new pages which are written completely in React and uses hashtag navigation. In main entry file index.js there is redux-router hierarchy and it expects that it runs on purely React page. This actually does not match with demand to embed some components into JSP/XSLT static page with classical URL navigation, right?

But I would like to share React components between brand new react pages and legacy XSLT pages! And at some moment just compose React page from existing components and abandon legacy ones. So how to do that?

  1. Prepare second entry file (like indexLegacy.js) and prepare build task for it (we use Webpack).
  2. Insert result bundle file via <script src=’bundleLegacy.js’/> into JSP/XSLT pages right before </body> element.
  3. In JSP/XSLT/whatever page put empty DIV tag in place where React components should be rendered and give it nice id or class name – like “hack_legacy_tasks_list”.
  4. In new entry file write logic that basically perform list of IFs that fills prepared DIVs – but only if they exists:
    • Check if desired element with unique name is presented in DOM (we use jQuery for that)
    • If it is presented render desired component into it (using React.render(<MyComponent>, element))
  5. Of course list of IFs can be replaced by some metadata and have generic code that process them.
  6. If component needs some context, you can wrap it. But you have to do it for all of them separately. They do not share tree hierarchy (React instance).
  7. If all components on page needs to share something, it can be instantiated in entry file and passed to all components.

That’s it. Lets sum up some advantages:

  • Components are shared between new shiny React pages and legacy pages.
  • There is single entry bundle for legacy stuff. If your legacy pages includes shared footer file you can place reference to legacy bundle there. Because unique ids/classnames are used for binding, it should not harm any existing content.
  • You may place multiple components per legacy page – insert multiple DIVs.

React.js FTW!

Here is sample of indexLegacy.js

//libraries
import React from "react"
import {render} from "react-dom"
import moment from "moment"

import jQuery from 'jquery'

import {Utils} from './utils/Utils'

//container for legacy components
import {LegacyApp} from './containers/LegacyApp'

import {ReactDemo} from './quark/ReactDemo'
//...and other 10+ components

//key is CSS selector, value is function that returns React element
const instances = {
  '.hack_react_demo': (elem)=><ReactDemo/>   //this defines method that creates React component for HTML element <div class='hack_react_demo'/> placed everywhere
  //...and other 10+ components
}
 
//render reactElement into DOM elemenet wrapped by LegacyApp
function __createReactInstance(element, reactElement) {
  render(<LegacyApp>{reactElement}</LegacyApp>, element)
}

//for each entry in instances object
Object.keys(instances).forEach(selector=>{
    //for each DOM element found by jQuery
    jQuery(selector).each((i, element)=>{
      //get function for selector and call it (passing DOM element)
      const reactElement = instances[selector](element)

      //create React component
      __createReactInstance(element, reactElement)
    })
  })