Category: Frontend

From MVC to Redux

From MVC to Redux

If you come from MVC or one of its brothers/cousins/incredible mutations, this diagram should be familiar to you:

Mvc to redux: MVC worflow

The user action triggers a call to a controller, who updates the model and refreshes the view.

THE PROBLEM: NON-DETERMINISTIC UI

This works well when you have few controllers and views, but it gets really messy as the application’s complexity increases. The complete model is exposed through several controllers, so you will need to orchestrate calls from one controller to another, making it really hard to tell where a certain change came from or which is the complete state of the application at a specific point.

The fact that views make asynchronous calls to this controllers will add an extra difficulty to your confused and ephemeral life and then you will be ready to love Redux:

Mvc to redux: Redux worflow

 

REDUX TO THE RESCUCE

In Redux, the state is an object that contains the whole model of your application, like a big tree with all your application’s data. This object has no setters, as you cannot modify the state directly. Did you see where state sits in the diagram? It can only be accessed by the Reducers.

Instead of setting properties in the state, each component can dispatch actions to the store and those actions will be translated into state changes.

The actions are plain javascript objects also, describing the intention of modifying the state, like:

{ "UPDATE_COMPANY", company: newCompanyData } 

The reducers are a set of chained functions that take this action and the current state and return a new complete state tree.

reducer(oldState, // { user: user, company: null}
  action);        // { "UPDATE_COMPANY", company: newCompanyData } 

//returns new object { user: user, company: newCompanyData }

Once the reducers have been executed, the Redux store saves this object as state, and every component listening to the store changes will now be updated.

Like in the CQRS pattern, the model used to update information(dispatch an action) is different than the model used to read it (subscribe to store changes).

ADVANTAGES:

-As you are holding the state in a single object, you can recreate the state easily and the application becomes much easier to test.
-As the reducers are pure functions (they always return the same output for a given input), you can undo and time-travel the states, which helps a lot with debugging.

 

More on…

Redux basics: https://redux.js.org/basics/actions

Event sourcing: http://microservices.io/patterns/data/event-sourcing.html

CQRS: https://martinfowler.com/bliki/CQRS.html

Unidirectional UI: https://staltz.com/unidirectional-user-interface-architectures.html

Thinking in Redux: https://hackernoon.com/thinking-in-redux-when-all-youve-known-is-mvc-c78a74d35133

Thoughts on modular CSS

Thoughts on modular CSS

There was a time when I always asked myself which level of specificity should I reach when writing my CSS code. It is so easy to nest selectors without touching the HTML markup, write top level selectors for things like ‘h2’ or ‘a’… And end up rewriting rules, re-rewriting, un-writing the rewritten…

The problem with CSS is that multiple rules can be applied to the same element. This is a problem because developers tend to write generic rules and because some of the CSS properties are inherited till the infinity and beyond. I learned from OOP (Java) that you have to use inheritance when the object that is inheriting the properties is-a parent object. This is CSS, so forget those semantical nuances; if your parent has ‘Lato’ font, you have ‘Lato’ font. I do not mind if your parent is a Cat and you are a Ford Cortina.

In most of the situations, it is a good idea to:

  • Scope or namespace your selectors to reduce the specifity (BEM)
  • Bind your styles to classes and not to HTML tags, to avoid polluting the tags in all your application with styles that are tied only to a specific component (Opt-in Typography)

BEM (block__element–modifier)

This naming convention will help you to set a very low level specificity in your selectors while communicating the HTML structure of your components by simply looking at the CSS.

<!-- CLASSIC STYLING -->

<section class="avatar">

<img src="avatar.jpg">

<span>KoolUsername99</span>

</section>



<style>

.avatar { } /* Specificity of 10 */

.avatar img { } /* Specificity of 11 */

.avatar span { } /* Specificity of 11 */

</style>

This is good… to an extent. As the SaSS documents say “Be aware that overly nested rules will result in over-qualified CSS that could prove hard to maintain and is generally considered bad practice“.

In modular applications, this works better:

<!-- BEM STYLING -->

<section class="avatar">

<img class="avatar__img" src="avatar .jpg">

<span class="avatar__span">KoolUsername99</span>

</section>



<style>

.avatar { } /* Specificity of 10 */

.avatar __img { } /* Specificity of 10 */

.avatar __span { } /* Specificity of 10 */

</style>

Looks verbose, but ends up being much more maintainable and clearer.

Opt-in Typography

This is a simple idea took from a Chris Eppstein (core team of SaSS) talk. Instead setting global styles for typographic elements like h1, he proposes to apply those styles as a class (.h1 or .title) to avoid tying presentation to the base tags.

Backbone + React

Backbone + React

Some time ago a teammate and I implemented some POC with Backbone and React and from the beginning I thought it would be interesting to combine these two frameworks, as Backbone only provides a lightweight base for scaffolding the app and React seems a very powerful library to build the UI. But the first implementation I tried made use of JSX, from React Tools, which has been deprecated in favor of Babel (Facebook’s React Blog).

This post documents my second attempt of integrating Backbone with React in a web application that uses RequireJS to define modules and Grunt to preprocess the JSX files and wrap everything up.

Backbone + React example I

You can download the full source code of this example at Github.

Backbone + React example I

 

This is the folder structure. The “src” folder contains all the source files, that will be proccessed by a Grunt build script, putting the resulting file structure inside “dist” folder.

 

 

 

 

 

Ok, let’s see the code…

  <body>
        <script data-main="js/main" src="../node_modules/requirejs/require.js"></script>
  </body>    
  • index.html: Will only load require.js and refers to main.js as our application’s entry point. All the HTML content of the different views of the app will be located in React components. We will compose these views with Backbone.
'use strict';
require.config({
    // shim: scripts that do not call define() to register a module
    shim: {
        underscore: {
            exports: '_'
        },
        backbone: {
            deps: [
                'underscore',
                'jquery'
            ],
            exports: 'Backbone'
        },
        backboneLocalstorage: {
            deps: ['backbone'],
            exports: 'Store'
        }
    },
    paths: {
        'jquery': '../../node_modules/jquery/dist/jquery',
        'underscore': '../../node_modules/underscore/underscore',
        'backbone': '../../node_modules/backbone/backbone',
        'text': '../../node_modules/requirejs-text/text',
        'react': '../../libs/react',
        'ReactDOM': '../../libs/react-dom'
    }
});

define([
    'backbone',
    'views/MainView'
], function(Backbone, MainView) {
    'use strict';
    return Backbone.Router.extend({
        init: function() {
            window.app = {};
            window.app.vent = _.extend(Backbone.Events);    
            new MainView();
        }            
    });
});
  • main.js: This file contains the RequireJS configuration. The shim field is used to configure dependencies for scripts that do not call define() to register a module. The paths field contains shortcuts to the different libraries that we will use. Backbone has underscore and jQuery as dependencies, so we are loading all of them, and React on its side is split into React and ReactDom.
define([
    'underscore',
    'backbone',
    'views/HeadView',
    'text!templates/main.html'
], function(_, Backbone, HeadView, mainTemplate) {
    'use strict';

    return Backbone.View.extend({
        el: 'body',
        template: _.template(mainTemplate),
        events: {},
        initialize: function() {
            this.render();
        },
        render: function() {
            this.$el.html(this.template({}));
            this.postRender();
        },
        postRender: function(){
            this.headRegion = this.$('#head-region');
            if (!this.headView) {
                this.headView = new HeadView();
            }
            var props  = {title: 'Header Title'};
            this.headView.render(this.headRegion, props);    
        }
    });
});
  • MainView.js: Is a Backbone View that will use a standard way of rendering HTML templates with underscore & text. With this configuration, we can use either React or underscore to render the HTML corresponding to a Backbone View. After MainView renders its contents, it will render the React component inside the header DOM element (#head-region), passing the title property to the component.

 

define([
    'backbone',
    'ReactDOM',
    'react',
    'components/HeadComponent'
], function(Backbone, ReactDOM, React, HeadComponent) {
    'use strict';

    return Backbone.View.extend({
        events: {},
        initialize: function() {},
        render: function(el, props) {
            //Create React Element based on HeadComponent.jsx
            this.reactElement = React.createElement(HeadComponent, {
                view: this,
                title: props.title
            });
            //Render element into DOM element passed from parent view
            ReactDOM.render(this.reactElement, el[0]);
        }

    });
});
  • HeadView.js: Here is when we start using React. The HeadView is a Backbone View that receives a DOM element as parameter in its render method. We will call React.createElement() passing to the call the JSX component and the title we received from MainView. Once the element has been created, we call ReactDOM.render() to actually insert the rendered contents into the DOM.

 

define([
    'react',
], function(React) {
    'use strict';
    return React.createClass({
    render : function() {
        return (
            <div>
            <span id="header-title">{this.props.title}</span>
            </div>
        );
    }
  });
});
  • HeaderComponent.jsx: It is a simple header that will take a string named “title” as parameter and render a span with the received string. The props field of a React element is populated with the properties passed to the React.createElement() call that is made to create that element.
module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);
  grunt.loadNpmTasks('grunt-execute');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-express');  

  grunt.initConfig({

    clean: ["dist"],

    babel: {
      options: {
        sourceMap: false,
        modules: "common"
      },
      dist: {
        files: [{
          expand: true,
          cwd: 'src',
          src: ['js/components/*.jsx'],
          dest: 'dist',
          ext: '.js'
        }]
      }
    },

    copy: {
      main: {
        files: [{
          expand: true,
          src: ['**/**', '!**/components/**'],
          dest: 'dist/',
          cwd: 'src',
          filter: 'isFile'
        }],
      },
      libs: {
        files: [{
          expand: true,
          src: ['libs/**'],
          dest: 'dist/'
        }],
      },
      node_modules: {
        files: [{
          expand: true,
          src: [
            'node_modules/requirejs/require.js',
            'node_modules/jquery/dist/jquery.js',
            'node_modules/underscore/underscore.js',
            'node_modules/requirejs-text/text.js',
            'node_modules/react/**',
            'node_modules/react-dom/dist/react-dom.js',
            'node_modules/backbone/backbone.js'
          ],
          dest: 'dist/'
        }],
      }
    },
    express: {
      all: {
        options: {
          port: 3000,
          hostname: 'localhost',
          bases: ['./dist'],
          livereload: true
        }
      }
    },
    watch: {
      scripts: {
        files: ['src/**/*.js', '!src/js/components/**'],
        tasks: ['copy'],
        options: {
          spawn: false,
          livereload: true
        },
      },
    }

  });
  grunt.registerTask('server',['express','watch']);
  grunt.registerTask('default', ['clean', 'copy', 'babel', 'server']);

};
  • gruntfile.js: A simple Grunt script to copy all the source files to “dist” folder, process the JSX files with Babel and open a light node server.

 

Next steps I plan to take are to add some user interaction, handling the events with React and implement the Backend calls with Backbone Models. And Webpack maybe.

Still there? You are awesome <3