Capgemini

ReactJS training.

Bartek Pietrowski

Agenda

  1. ES6 wrap-up
  2. Functional Programming
  3. Create React App
  4. ReactJS
    • Syntax
    • Patterns
    • Good practices
    • > v.16
  5. React ecosystem
  6. Project experiences

ES6
wrap-up

js logo

let and const


        function f() {
          {
            let x;
            {
              // this is ok since it's a block scoped name
              const x = 'sneaky';
              // error, was just defined with `const` above
              x = 'foo';
            }
            // this is ok since it was declared with `let`
            x = 'bar';
            // error, already declared above in this block
            let x = 'inner';
          }
        }
      

let and const


        for (var i of [1,2,3]){
          setTimeout(()=>console.log(i),0)
        } 

        // vs.
        
        for (let i of [1,2,3]){
          setTimeout(()=>console.log(i),0)
        }
      

let and const


        for (let i of [1,2,3]){
          setTimeout(()=>console.log(i),0)
        }

        // would be in ES5 sth like:

        for (var i of [1,2,3]){
          ((index) => setTimeout(()=>console.log(index),0))(i)
        } 
      

Enhanced object literals


        const obj = {
          // Sets the prototype.
          __proto__: theProtoObj,
          // Shorthand for 'handler: handler'
          handler,
          // Methods
          toString() {
            // Super calls
            return 'd ' + super.toString();
          },
          // Computed (dynamic) property names
          [ 'prop_' + (() => 42)() ]: 42
        };
      

Template Strings


        // Basic literal string creation
        `This is a pretty little template string.`
        
        // Multiline strings
        `In ES5 this is
          not legal.`
        
        // Interpolate variable bindings
        const name = 'Bob', time = 'today';
        `Hello ${name}, how are you ${time}?`
        
        // Unescaped template strings
        String.raw`In ES5 "\n" is a line-feed.`
      

Arrow functions


        // Expression bodies
        const incr = [1,2,3].map(v => v + 1);
        const nums = [1,2,3].map((v, i) => v + i);

        // Statement bodies
        nums.forEach(v => {
          if (v % 5 === 0)
            console.log(v);
        });
      

Lexical This


        const bob = {
          _name: 'Bob',
          _friends: ['Anna'],
          printFriends() {
            this._friends.forEach(f =>
              console.log(`${this._name} knows ${f}`)
            );
          }
        };
      

Useful methods

  • [].includes()
  • [].some()
  • [].every()
  • [].filter()
  • [].map()
  • [].reduce()
  • [].findIndex()
  • Object.entries()
  • Object.keys()
  • Object.values()
  • Object.assign()

Spread operator


        function f(x, y, z) {
          return x + y + z;
        }
        // Pass each elem of array as argument
        f(...[1,2,3]) === 6 // true


        const g = (x, ...y) => {
          // y is an Array
          return x * y.length;
        }
        g(3, 'hello', true) === 6 // true
      

Destructuring


        // arrays
        const [a, ,b] = [1,2,3];
        const [a, ...b] = [1,2,3];
        // objects
        const {documentElement, ...other} = document;
        console.log(documentElement);
        console.log(other.location);
        // Fail-soft destructuring with defaults
        const [a = 1] = [];
        a === 1;
        // Object.assign alternative
        {...{a: 'a', b:2, c:3}, ...{b:100, d: 'd'}}
      

-> Example - in iteration <-

Default parameters


          const f = (x, y = 12) => {
            // y is 12 if not passed (or passed as undefined)
            return x + y;
          }
          f(3) === 15 // true

          // with destructuring
          const f = ({x:alias = 1, y = 12} = {}) => {
            return alias + y;
          }
        

Iterators + For..Of


        const fibonacci = {
          [Symbol.iterator]() {
            let pre = 0, cur = 1;
            return {
              next() {
                [pre, cur] = [cur, pre + cur];
                return { done: false, value: cur }
              }
            }
          }
        }
        
        for (let n of fibonacci) {
          // truncate the sequence at 1000
          if (n > 1000)
            break;
          console.log(n);
        }
      

Generators


        const fibonacci = {
          [Symbol.iterator]: function*() {
            var pre = 0, cur = 1;
            for (;;) {
              [pre, cur] = [cur, pre + cur];
              yield cur;
            }
          }
        }
      

Modules


        // lib/math.js
        export function sum(x, y) {
          return x + y;
        }
        export const pi = 3.141593;
        // app.js
        import * as math from "lib/math";
        console.log(`2π = ${math.sum(math.pi, math.pi)}`);
        // otherApp.js
        import {sum, pi} from "lib/math";
        console.log(`2π = ${sum(pi, pi)}`);
        // i.do.not.like.default.export.js
        export default function(x) {
            return Math.exp(x);
        }
      

-> Why I do not like default export <-

Map + Set + WeakMap + WeakSet


          // Sets
          const s = new Set();
          s.add('hello').add('goodbye').add('hello');
          s.size === 2;
          s.has('hello') === true;
          
          // Maps
          const m = new Map();
          m.set('hello', 42);
          m.set(s, 34);
          m.get(s) == 34;
          
          // Weak Maps
          const wm = new WeakMap();
          wm.set(s, { extra: 42 });
          wm.size === undefined
          
          // Weak Sets
          const ws = new WeakSet();
          ws.add({ data: 42 });
          // Because the added object has no other references, 
          // it will not be held in the set
      

Proxies


          // Proxying a normal object
          const target = {};
          const handler = {
            get: function (receiver, name) {
              return `Hello, ${name}!`;
            }
          };
          
          const p = new Proxy(target, handler);
          p.world === 'Hello, world!';
      

Proxies


          const target = function () { return 'I am the target'; };
          const handler = {
            apply: function (receiver, ...args) {
              return `I am the proxy -> ${receiver()}`;
            }
          };

          const p = new Proxy(target, handler);
          p(); // "I am the proxy -> I am the target"
      

Classes (*)


          class SkinnedMesh extends THREE.Mesh {
            constructor(geometry, materials) {
              super(geometry, materials);
          
              this.idMatrix = SkinnedMesh.defaultMatrix();
              this.bones = [];
              this.boneMatrices = [];
              //...
            }
            update(camera) {
              //...
              super.update();
            }
            static defaultMatrix() {
              return new THREE.Matrix4();
            }
          }
      

Promises


        function timeout(duration = 0) {
          return new Promise((resolve, reject) => {
              setTimeout(resolve, duration);
          })
        }
        
        const p = timeout(1000).then(() => {
            return timeout(2000);
        }).then(() => {
            throw new Error('hmm');
        }).catch(err => Promise.all([
            timeout(100).then(()=>100), 
            timeout(200).then(()=>200)
          ])
        ).then(console.log)
      

Promises with async await


        async function timeout(duration = 0) {
          return new Promise((resolve, reject) => {
              setTimeout(resolve, duration);
          })
        }
        
        await timeout(1000);
        await timeout(2000);
        try {
          throw new Error('hmm');        
        } catch (err) {
          const data = await Promise.all([
            timeout(100).then(()=>100), 
            timeout(200).then(()=>200)
          ]);
          console.log(data);
        }
      

RORO pattern


          async saveUser({
            upsert = true,
            transaction,
            ...userInfo
          }) {
            // save to the DB
            return {
              operation, // e.g 'INSERT'
              status, // e.g. 'Success'
              saved: userInfo
            }
          }
      

Read more

Functional Programming

Why functional programming?

  • Pure Functions
  • Immutability
  • No Side-effects
  • Easier to understand
  • Easier to test

Non-functional solution


            const arr = [1,2,3,4,5,6,7,8,9]
            
            function getOdds(arr) {
                let odds = []
                for(let i = 0; i < arr.length; i++) {
                    if( i % 2 !== 0) {
                        odds.push(i)
                    }
                }
                return odds
            }

            console.log(getOdds(arr))
            // logs [1, 3, 5, 7, 9]
        

functional solution


            function getOdds(arr) {
                return arr.filter(num => num % 2 !== 0)
            }

            console.log(getOdds(arr))
            // logs [1, 3, 5, 7, 9]

            //even shorter
            const getOdds2 = arr => arr.filter(num => num % 2 !== 0)
        

currying


            function add(x) {
                return function add(y) {
                    return x + y
                }
            }

            // better
            const add = x =>
                y =>
                    x + y
                
            console.log(add(3)(4)) // 7
            const add3 = add(3)
            console.log(add3(4)) // 7
            console.log(add3(5)) // 8
        

2nd example


            const createDivideFilter = divFactor => 
                x => 
                    (x % divFactor===0)
                
            ([...Array(20)].map((v, i) => i).filter(createDivideFilter(2)))
            // [ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 ]
        

Enter
React JS

What is React?

  1. Efficient Javascript library for building UIs
  2. Focuses on rendering data
  3. Virtual DOM, granular updates
  4. Declarative
  5. Component-Based
  6. Highly popular library

Smallest React example


          ReactDOM.render(
            <h1>Hello, world!</h1>,
            document.getElementById('root')
          );
      

Create react app

  1. Empty React project template
  2. No configuration required
  3. One dependency
  4. No Lock-In
  5. Good practices in place
  6. Plenty of hints in the docs
  7. Extremely popular - good community support

Our first React component


        class HelloWorld extends Component {
          render() {
            return (
              <div className="hello">
                Hello World
              </div>
            );
          }
        }
        // usage example: <HelloWorld/>
      

But what is this funny JS and XML mixup?

JSX!

  • Syntax Extension to Javascript
  • Compiles to Javascript
  • Prevents Injection Attacks

JSX to Javascript


            const element = (
                

Hello, World!

) // Babel compiles it to const element = React.createElement( 'h1', {className: 'hello'}, 'Hello, World!' )

Passing Data Through Props - Parent


        export class App extends Component {
          world = 'World';
          render() {
            return (
                <div className="book-app">
                  <Hello who={this.world} />
                </div>
              );
          }
        }
      

Passing Data Through Props - Child


        export class Hello extends Component {
          render() {
            const { who } = this.props;
            return <span className="hello">Hello {who}</span>;
          }
        }
      

Props are read only!

Interactive Component - state + event handling


          export class Hello extends Component {
            constructor(props) {
              super(props);
              this.state = {
                who: props.who,
              };
            }
            onWhoChange(e) {
              e.preventDefault();
              this.setState({
                  who: e.target.value,
              });
            }
            render() {
              const { who } = this.state;
              return (
                <div className="hello-container">   
                  <span className="hello">Hello {who}</span>
                  <input value={who} 
                    type="text"               
                    onChange={(e) => this.onWhoChange(e)}
                  />
                </div>   
              );
            }
          }
      

Improvements


          export class Hello extends Component {
            state = {
              who: this.props.who,
            }
            onWhoChange = e => {
              e.preventDefault()
              const who = e.target.value
              this.setState((prevState, props) => ({
                  who,
              }));
            }
            render() {
              const { who } = this.state;
              return (
                <div className="hello-container">   
                  <span className="hello">Hello {who}</span>
                  <input value={who} 
                    type="text"               
                    onChange={this.onWhoChange}
                  />
                </div>   
              );
            }
          }
      

Dumb and smart components

Smart Component


            class Hello extends Component {
              state = {
                who: this.props.who,
              };
            
              onWhoChange = (e) => {
                e.preventDefault();
                const who = e.target.value;
                this.setState((prevState, props) => ({
                    who,
                }));
              }
            
              render() {
                const { who } = this.state;
                return (
                  <DumbHello who={who} onWhoChange={this.onWhoChange} />   
                );
              }
            }
        

Dumb Component


          const DumbHello = ({ who, onWhoChange }) => (
            
Hello {who}
);

Lifecycle methods

Check here

Pure Functional Component


            const element = () => (
                
Hello World
)

Layout / slot components

Task 1 - simple details component

HOCs

Render props

Task 2 - master details view

Http

React v.16

Useful Libraries

VSCode extensions

Browser Plugins

React docs

Redux intro

  • State container for Javascript apps
  • Inspired by Flux Design Pattern, CQRS, and Event Sourcing
  • Application logic can only be changed on a single place
  • Great DEV experience - Hot Reloading with Time Travel

Three Principles

  • Single source of truth
  • State is read-only
  • Changes are made with pure functions (reducers)

Flux Flow

State


          {
            todos: [{
              text: 'Eat food',
              completed: true
            }, {
              text: 'Exercise',
              completed: false
            }],
          }
      

Action


          { 
            type: 'ADD_TODO',
            text: 'Go to swimming pool' 
          }
      

Reducer


          function todos(state = [], action) {
            switch (action.type) {
              case 'ADD_TODO':
                return state.concat([{ text: action.text, completed: false }])
              default:
                return state
            }
          }
      

New State


            {
              todos: [{
                text: 'Eat food',
                completed: true
              }, {
                text: 'Exercise',
                completed: false
              }, {
                text: 'Go to swimming pool',
                completed: false
              }],
            }
        

Redux