Posted on :: 3676 Words :: Tags: ,

Introduction

This post starts a new series in this blog talking about a famous Javascript Framework named React JS. React is a reactive framework which aims for better responsiveness of the application where parts of your system "listen" to each other and at any change they react to it by doing some action like re-rendering or fetching data from a backend server, etc. This is an evolution of the Observable Pattern.

To better focus on React in these posts I will not talk about NodeJS and Webpack but if you want/need to learn these two things please refer to these previous posts I made:

  1. NodeJS- A very simple introduction
  2. Webpack- A complete introduction
  3. Webpack- Starting a frontend

All of them teaches with practice and working codes, what you have to do to have a functioning basic Node/Webpack application with SASS. But if you already have knowledge on all of these and only want to focus on learning React, clone my bitbucket repo and checkout webpack_frontend branch:

git clone https://bitbucket.org/kiberStender/node_app.git
cd node_app/
git checkout --track origin/webpack_frontend

This branch has all the code developed throughout the three posts above. Everything said let's dive in and learn about React.

React JS

What does exactly React JS do that deserves your attention? I'm going to show you two pieces of code and I want you try to figure out which one executes faster:

  1. let arr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
    let ul = document.querySelector("#a_ul"); // an unordered list <ul id="a_ul"><ul/>
    
    for (const item of arr) {
      ul.innerHTML += `<li>${item}</li>`;
    }
    
  2. let arr = [
      0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
      21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
      41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,
      61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
      81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100
    ];
    let ul = document.querySelector("#a_ul"); // an unordered list <ul id="a_ul"><ul/>
    
    ul.innerHTML = arr.reduce((acc, item) => `${acc}<li>${item}</li>`, "")
    

If you are not well experienced with Javascript you would say that the first one is faster, because it's only 21 items. The thing here is: innerHTML is not a simple variable. Any changes to this triggers I/O(Input/Output) operations in your browser. I/O is a very expensive operation and not only expensive but unlike changing a variable value, doing I/O can fail due to many possible problems(like too much delay to process due to lack of cpu or memory resources at the time so browser cancel your IO operation) and given the decision of making it a variable instead of a function for example, it is not visible by the developer that it can fail and error may arise by lack of attention.

By executing the first code we are triggering 21 I/O operations while in the second piece of code, even though we have a bigger loop (101 items) we only do one I/O operation.

And what does React has to do with it?

React works with the idea of controlling the number of I/O operations you do by not allowing you to do it yourself. But how can React know when to perform I/O and when not? React performs comparison of variables, so whenever a variable changes something React triggers re-render operations only on the parts of your code that are affected by that value that changed. To control it, Reacts wants you to not change variables directly:

let a = 10
a = 5 // Do not do this

React has an 'interface' where it has a function/method named setState and by using this function, you control rendering or let React knows when a variable has changed and then triggers re-render operation(more on this later). By doing so, React always knows when and how many I/O to be performed, because it controls what it calls Components and any Component inside the Component that triggered setState will be updated too.

Instead of doing one I/O per Component it does what the function reduce does to the array, processing everything in one single batch and then returns a single object to React to do the I/O.

Adding React to our codebase

Now, before I go any further in explanation, let's re-write our simple "Hello World". The first thing we have to do is to add React in our dependency list. React is a framework like Bootstrap, so we're adding it to normal dependency list not the dev-dependency list:

npm install react@16.13.1 react-dom@16.13.1

PS: To guarantee that everything will work in the future as it is working right now, please install all the dependencies in the same version I put here in the snippet

React itself is inside react library, for now don't focus on react-dom as we will only use it in the application's start. Now go to your /src/javascript/greetings/DateGreetings.js file and change it to the given example:

import React from "react"; // 1
import moment from "moment";

import "greetings/dateTimeGreetings.scss";

export default (props/*3*/) => React.createElement( // 2
  'div', {id:"date-time-greetings-component"}, `It is: ${moment().format(props.dateFormat)}` // 4
);

Let's go to the explanation:

  1. The first thing to be done is import React to your code
  2. Then make DateTimeGreetings class to become a function
  3. I will explain props later but, essencially it is an object with external values that whoever is using your Component pass to instante it
  4. Notice that now it is using props.dateFormat instead of dateFormat because now, dateFormat is passed via props not via constructor

React.createElement

In what is called vanilla Javascript there is a function named document.createElement which only receive one parameter, a string containing the name of the TAG you want to create and returns and instance of DOM Node. With this Node instance you can "populate" it with attributes like id, css class(es), etc:

const div = document.createElement("div");
div.setAttribute("id", "my-div");
div.classList.add("my-css-class");
div.classList.add("my-css-class-2");

And then you can programatically control your page adding or removing Nodes or Node attributes when some button is clicked or some input data is given. But, as you may take notice, I had to write 4 lines to describe one single div that has actually 2 attributes(id and class). React thought about that and created their own createElement function were one can do this in a shorter way:

const div = React.createElement("div", {id:"my-div", className:["my-css-class", "my-css-class-2"]});

Not only it is shorter but easier to understando too. And this is the whole base of React, all the fuss you eard about is because of this piece of function. With this you can create programatically create your whole page deciding when something will be rendered and when not.

JSX

Wait a minute... What is this strange syntax? This is probably not what you have seen so far when people talk about React. You probably have seen React like this:

import React from "react";
import moment from "moment";

import "greetings/dateTimeGreetings.scss";

export default (props) => (
  <div id="date-time-greetings-component">
    It is: {moment().format(this.props.dateFormat)}
  </div>
)

So how to achieve this? This HTML syntax in the middle of the Javascript is called JSX. It is a transpiled language in the middle of the transpiled Javascript that is transformed in this 'weird' syntax seen above. To have this syntax in your code making it easier to write and read, you have to simply add another preset in our Babel configuration (in babel.config.js file). First install babel react preset:

npm install --save-dev @babel/preset-react@7.9.4

Now go to /babel.config.js and add the newly installed preset to our config:

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        targets: {
          node: "current",
        },
      },
    ],
    "@babel/preset-react",
  ],
};

PS: Whenever you see three dots ..., it means: "keep whatever comes before this". Or if it comes after what we are adding/modifying, it means: "keep whatever comes after these dots"

Now "reactify" /src/javascript/greetings/Greetings:

import React from "react"; // 1 
import DateTimeGreetings from "greetings/DateTimeGreetings.js"; // 2
import Person from "person/Person";

import "greetings/greetings.scss";

export default class Greetings extends React.Component { // 3  
  render(){ // 4
    const {name, surname} = this.props.person ? this.props.person : new Person("Unnamed", "Person"); // 5
    
    return React.createElement(
      "div", 
      {id: "greetings-component"},
      `Hello Mr/Ms ${name} ${surname}`,
      React.createElement(DateTimeGreetings, {dateFormat: "MMMM Do YYYY, h:mm:ss a"}) // 6
    );
  }
}

Allow me to explain:

  1. Again import react
  2. Import our class newly transformed to Component DateTimeGreetings
  3. Make Greetings a Component too
  4. Change greet name to render
  5. Greetings now receive person parameter via props(Calm down I will explain what props are) instead of via direct this as it was done previously
  6. Instantiate DateTimeGreetings as if it was one of the React's pre-defined HTML tags and pass dateFormat via props to the instance of the class

Update /src/javascript/App.js:

import React from "react";
import Person from "person/Person";
import Greetings from "greetings/Greetings";

import "app.scss";

export default class App extends React.Component{

  render(){
    const person = new Person("John", "Titor");
    return React.createElement(
      "div", 
      {id: "greetings-example"}, 
      React.createElement("h1", null, "Greetings Example"), 
      React.createElement(Greetings, {person: person})
    );
  }
}

I don't think there is much to be explained here that was not explained in the previous examples. At last, go to /src/index.js file and change it to this:

import React from "react"; //1
import ReactDOM from "react-dom"; //2
import App from "App";

ReactDOM.render( // 3
  React.createElement(App, null), // 4
  document.querySelector("#root") // 5
);

Explaning:

  1. Like previously, import React to our code
  2. Now import ReactDOM. This is the 'engine' of React. This is what makes React works the way it works. If you know Java, think about the class Thread. Just by creating an instance of this class won't make it work. You need to call start method and you will need to specify an Executor (usually GlobalExecutor) and then your Thread "will be executed"(If there are resources for it). If you are not Java dev or not familiarized with Thread class, React Dom is what starts your React app and control the lifecycle
  3. Here is where the command to React-DOM start the application to run is given
  4. Creating an element of type App, like it was done with Greetings and DateTimeGreetings previously in other components
  5. Here we say where we want our react app to be rendered. If for some reason you want to have a second app you can simply call ReactDOM.render again passing a different document.querySelector("another_element")

And voi là. To guarantee to you that it is working and it is not a cache, I changed "Node Dev" to "John Titor". So check it, if you see the different name, you can be sure you did everything correctly. Run now using npm run-script live and go to http://localhost:8080

Check out the generated pure HTML code:

And now you have React JS in your project. As you can see, React is not a framerwork to beautify your app, like for example, when you are learning JQuery. Even though you can use JQuery without adding CSS dynamically, it is counter intuitive. React is made for you to focus in the structure of you HTML and how to dinamically change values diminishing the maximum possible I/O operations. If you compare it to jQuery that does I/O almost all the time, React is mostly to improve performance while keeping your code (more) readable.

JSX

Wait a minute... What is this strange syntax? This is probably not what you have seen so far when people talk about React. You probably have seen React like this:

import React from "react";
import moment from "moment";

import "greetings/dateTimeGreetings.scss";

export default class DateTimeGreetings extends React.Component {  
  render(){
    return (
      <div id="date-time-greetings-component">
        It is: {moment().format(this.props.dateFormat)}
      </div>
    )
  }
}

So how to achieve this? This HTML syntax in the middle of the Javascript is called JSX. It is a transpiled language in the middle of the transpiled Javascript that is transformed in this 'weird' syntax seen above. To have this syntax in your code making it easier to write and read, you have to simply add another preset in our Babel configuration (in babel.config.js file). First install babel react preset:

npm install --save-dev @babel/preset-react@7.9.4

Now go to /babel.config.js and add the newly installed preset to our config:

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        targets: {
          node: "current",
        },
      },
    ],
    "@babel/preset-react",
  ],
};

PS: Whenever you see three dots ..., it means: "keep whatever comes before this". Or if it comes after what we are adding/modifying, it means: "keep whatever comes after these dots"

Now You can start writing JSX HTML inside your Javascript files and Babel will transpile it correctly.

  1. /src/javascript/greetings/DateTimeGreetings.js
    ...
    render(){
      return <div id="date-time-greetings-component">It is: {moment().format(this.props.dateFormat)}</div>
    }
    ...
    
  2. /src/javascript/greetings/Greetings.js
    ...
    render(){
      const {name, surname} = this.props.person ? this.props.person : new Person("Unnamed", "Person");
    
      return (
        <div id="greetings-component">
          Hello Mr/Ms {name} {surname}
          <DateTimeGreetings dateFormat="MMMM Do YYYY, h:mm:ss a" />
        </div>
      );
    }
    ...
    
  3. /src/javascript/App.js:
    ...
    render(){
      const person = new Person("John", "Titor");
      return (
        <div id="greetings-example">
          <h1>Greetings Example</h1>
          <Greetings person={person} />
        </div>
      );
    }
    ...
    
  4. /src/index.js
    ...
    ReactDOM.render(<App />, document.querySelector("#root"));
    

React.createElement and JSX

Understanding how JSX is transformed to React.createElement can helps us understanding some informations we will see with more details in the next topics. First let's see createElement prototype:

React.createElement(
  type,
  [props],
  [...children]
)
  1. type: A string or object containing the component we are instantiating. For any native HTML Tag, you pass it as a String like 'div', 'span', 'article', etc. For your own defined Components such as our Greetings, you pass it not as a String but as a 'anonymous class definition' or a type if you prefer
  2. props: It's an object literal {} containing the values you want to pass to your instantiated Component. In the prototype it is surrounded by [] not to say it is an array, but to say that this is optional
  3. children: It is a varargs array that you can pass anything you want, as long as it is serializable to a String. Usually customized Components do not have children. It's not a rule, it is just that usually you don't nest things inside your own Component from outside the file defining it. In the prototype it is surrounded by [] not to say it is just an array, but to say that this is optional too

Non JSX version:

React.createElement(
  'div',
  {prop1:"string", prop2:a_variable},
  "child1", "child2", React.createElement('span', {id:"abc"}, 'text')
)

React.createElement(
  Greetings,
  {person: new Person("Javascript", "Dev")},
  "child1", "child2", React.createElement(AComponent, {id:"abc"})
)

Now JSX representation:

<div prop1="string" prop2={a_variable}>
  child1
  child2
  <span id="abc">text</span>
</div>

<Greetings person={new Person("Javascript", "Dev")}>
  child1
  child2
  <AComponent id="abc"/>
</Greetings>

React Components

I mentioned a lot previously(here and here) that React has something named Component. But what is a Component? A Component can be two things:

  1. A function that returns a JSX/React.createElement:
    //1
    function Greeter(props){
      return <div id="greeter-component">{props.greet} {props.treatment} {props.name}</div>
    }
    //or
    //2
    function Greeter(props){
      return React.createElement('div', {id:"greeter-component"}, `${props.greet} ${props.treatment} ${props.name}`);
    }
    
    or
    //3
    const Greeter = (props) => <div id="greeter-component">{props.greet} {props.treatment} {props.name}</div>
    //or
    //4
    const Greeter = (props) => React.createElement('div', {id:"greeter-component"}, `${props.greet} ${props.treatment} ${props.name}`);
    
  2. A class that extends React.Component or React.PureComponent and has a method render that returns the JSX/React.createElement
    class Greeter extends React.Component {
      constructor(props){
        super(props)
      }
      render() {
        return <div>{this.props.greet} {this.props.treatment} {this.props.name}</div>
      }
    }
    //or
    class Greeter extends React.Component {
      constructor(props){
        super(props)
      }
      render() {
        return React.createElement('div', {id:"greeter-component"}, `${this.props.greet} ${this.props.treatment} ${this.props.name}`);
      }
    }
    
    PS: If you are not doing anything than calling super in your constructor, it is optional to have it:
    class Greeter extends React.Component {
      render() {
        return <div>{this.props.greet} {this.props.treatment} {this.props.name}</div>
      }
    }
    //or
    class Greeter extends React.Component {
      render() {
        return React.createElement('div', {id:"greeter-component"}, `${this.props.greet} ${this.props.treatment} ${this.props.name}`);
      }
    }
    

PS: Because of the interpreted nature of Javascript, you cannot jump lines after return otherwise the interpreter will return undefined. So if your JSX expression it too big you wrap parenthesis around it and you can jump as many lines as you want/need.

...
export default class SimpleMenu extends React.Component {
  render(){
    return (
      <div id="orkut-menu">
        <ul>
          <li>Home</li>
          <li>Friends</li>
          <li>Scraps</li>
        </ul>
      </div>
    )
  }
}

All of this to tell you that a Component is just you creating your own HTML Tag. By doing this, every Component you create is a part of your application, making it easier to compose these parts in the end, like it is just a big HTML file. If you run, you will notice that again nothing changed in the final result, but check the generated HTML:

Component as a Function vs as a Class

The advantage of having a Component as a function is that, it is less verbose and faster to be coded, see examples 1, 2, 3 and 4(specially 3 and 4). Usually you will use this way when you have a simple Component, such as our Greeter, that only displays something and has no interaction with the user like when you are creating a Header, Footer or any static part of your app that will not change by the Component own inner actions.

On the other hand having a Component as a class, will grant you way more control over your Component, because by then you will have support from React lifecycle and state changing using this.setState. You lose in amount of written code, but you gain in level of tunning or optimization of your Component.

But in any case, to change from a class to a function or vice-versa is not that hard, so if you're not sure what is the better approach to use, go for class approach, if you see that your Component is only changed by outside(via props), or you don't need to tune/lifecycle, you can easily change it to function approach later.

What are these "props"?

Props is short for "Properties". Think of your Component as a function, the props are your parameters, but instead of passing your parameters by position like you normally do in a function, here you are giving names to your parameters so you can pass them in any position.

Once you pass a props in your JSX or React.createElement you will have access to it inside your class/function that declares your Component using props.[the very same name] you declared outside your class/function when instantiating it. You can pass literally anything via props: functions, strings, int, double, complex objects, anything that Javascript allows you to put inside an object, because if you remember how we pass props in createElement function, it is just an object literal. See the example:

Declaring

Instantiating

Notice that props.greet in the first picture is being populated in the second picture via greet="Hello". If you forget to populate it like that, your props.greet will be undefined in your class/function. So always remember to either protect your props with some if else or to always populate your props correctly when instantianting your Component. See a simple example on how to protect your Component against undefined variables:

...
const Greeter = (props) => <div id="greeter-component">{props.greet ? props.greet : "Hello"} {props.treatment} {props.name}</div>
...

This way whoever is using your Greeter Component and forget to populate greet, the Component will assume it's value as "Hello".

How does it work internally?

Now that you understand that the core of the React is the React.createElement and everything revolves around it(even JSX that it is just a syntax sugar for this function), I created a simple code that actually does what React does. Of course it is very limited as it does not have State support, Lifecycles support, good perfomance, Virtual DOM, etc, etc. It is just a simple didactic example to better explain each part of what have been shown so far:

function createElement(type, props, ...children){
  return addChildren(createNode(type, props), children);
}

PS: You can check the whole code here

Notice that create element does 3(three) things:

  1. Create the HTML TAG:
    function createNode(type, props){
      if(typeof type === "string"){
        return addProps(document.createElement(type), props);
      } else {
        if(type.prototype instanceof Component){
          return new type(props).render();
        } else {
          throw new Error("Classes must extend Component");
        }
      }
    }
    
    React uses a class named Element created by React dev team that is later translated using the Virtual DOM. Don't take my code as a closer implementation to the original from React as in the original one Render is not the first function to be called in the lifecycle.
  2. Add the props:
    function addProps(element, props){
      for(const [key, value] of Object.entries(props)){
        switch(key){
          case "onclick"://Any other listener like ondbclick, onchange, onhover, etc
            element.addEventListener("click", value);
            break;
          default:
            element.setAttribute(key, value);
          break;
        }
      }
      return element;
    }
    
    The props here, as you can see, are the properties an HTML TAG can have. So if you know what properties an original HTML TAG it will be the same as passing them in pure HTML code. React is nothing more than you creating your own TAGs while composing original HTML and third parties TAGs created by other developers. And when you are creating your own TAG(a.k.a your own Component) you are free to give whatever name you want to your props. You will have access to them via this.props.theNameYouGaveWhenDeclaringYourTag.
  3. Add children to the TAGs:
    function addChildren(element, children){
      for(const child of children){
        if(typeof child === "object"){
          element.appendChild(child);
        } else {
          element.append(child);
        }    
      }
      return element;
    }
    
    This is complete optional as usually when you create your own TAG/Component, you don't need to have children because, you cannot control these children outside your TAG/Component. They will be handled by whoever is declaring your TAG/Component and in the perspective of your TAG/Component no child will be visible. Think about it as you declaring a div TAG with a ul inside it. The only thing the TAG div can actually see and control is its props because, in the perspective of the div it does not matter if it has child at all it is just a matter of structure.

So the state is ... ?

While props are external values provided to your Component via parent Component, they are fully immutable and changing them inside your Component won't trigger any re-rendering. So how can we mutate values to interact with our users? As mentioned in the beginning, React has a function named setState to deal with mutations that will only be available if your Component is a class extending React.Component or React.PureComponent. You have to create a variable named state(and pay attention to not give any other name, it has to be state) and this variable should be an object holding, if possible, only values (like String, Int, Double, Complex classes representing a value like Date) or anything that can be comparable:

...
constructor(props){
  super(props)
  this.state = {
    greet: "",
    treatment: "",
    title: "",
    aNumber: 0
  }
}
...

And in order to change one of those values you have to use setState like that:

...
myFunctionThatChangesGreet(newGreet){
  this.setState({greet: newGreet})
}
...

Or:

...
myFunctionThatIncrements(value){
  this.setState(state => ({aNumber: state.aNumber + value}))
}
...

Or:

...
myFunctionThatChangesGreetAndIncrementsANumber(newGreet, aNumberToIncrement){
  this.setState(state => ({aNumber: state.aNumber + aNumberToIncrement, greet: newGreet}))
}
...

Independently of what you choose to use (simple object passing or anonymous function passing) this command will trigger React to compare old greet with newGreet and aNumber to the new value to check if there are differences. If there are differeces, React re-renders your Component and any child inside it. Pay attention to this part React re-renders your Component and any child inside it. So if you don't break your application in as smaller Components as you can, you might have performance issues because it will have too many things to re-render everytime you change a single variable.

Changing treatment

All of these examples of how to change values inside this.state are awesome but, how actually to do this in real world? Let's add a input to allow the user to type what "treatment field" they want to be displayed instead of "Mr/Ms". Inputs in React are simple Components that demands you to bind/attach/implement the listener onChange and optionally bind/attach a variable to the props value. Bind/Attach are the terms used to describe when you are passing a variable to some prop in an given Component, in this case an input. This onChange is a listener and it is just a function with the signature:

onChange(event: Event): void

Let's modify our src/javascript/greetings/Greetings.js a bit so you can have an example:

...
  constructor(props){
    super(props);
    this.state = {
      treatment: ""
    }
  }
  
  whenTreatmentChanges(newValue){
    this.setState({treatment: newValue})
  }
  
  render(){
    return (
      <div id="greetings-component" className="a-class-that-changes-font-to-red">
        <div className="row">
          <div className="col-1">Treatment</div>
          <div className="col-2">
            <input value={this.state.treatment} onChange={event => this.whenTreatmentChanges(event.target.value)} />
          </div>
        </div>
        <Greeter greet="Hello" treatment={this.state.treatment} name={this.props.name} />
      </div>
    )
  }
...

setState callback

setState function is asynchronous, so if you change something outside another statement right after it in the next line expecting it to have the new values already it won't work. So if you need to fire something exactly when setState finishes updating your state variable, you can pass an anonymous function as a second parameter to setState:

...
whenTreatmentChanges(newValue){
  this.setState({treatment: newValue})
  console.log(this.state.treatment) // print old treatment value
}
...

This will show you the old value because as explained, setState is asynchronous, so in order to correctly do something after setState finishes updating you'll need to do the following way:

...
whenTreatmentChanges(newValue){
  this.setState({treatment: newValue}, () => console.log(this.state.treatment)) // print updated treatment value
}
...

Testing Components

Conclusion

We are going to stop it right here, because this is becoming too huge. So to not lose details, I'm leaving the more complex side of React to the next post . You learned in this post (I hope ^^) how to add React to your project, how to have JSX and what are the diffences when not using it, what props are, what Components are and how many types of Components we can have and how to deal with state.

We did almost no code here, we had more explanations than examples, but it was enough for you to have a good start with React. From this point on, you will be able to code an application in React even if you don't read next post(please do it xD). If by any chance you would like to read this in portuguese, feel free to go to the Brazilian Portuguese version of this page. See you next time.