We take developers from good to great

WE ARE THE JSLEAGUE

React.JS Intro

29th of March

Whoami

Sabin Marcu

Senior Software Engineer @ Hootsuite

Been working in web since '09

React Dev since 2015

React, GraphQL trainer @ JSLeague

JS (ES6)

Module 0

(arrays start at 0)

Fundamentals

Module 0

Classes

class MyClass extends Component {
    constructor() { ... }
    instanceProperty = 13;
    static classProperty = 42;
    method() { ... }
}

Const & Let

// ES6

var x = 25;

// ES6

const x = 25;
x = 15; // fail

let x = 25;
// ES5

for (var i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), i * 1000);
}

// ES6

for (let i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), i * 1000);
}

Module 0

Fat Arrow Functions (Lambda Functions)

// ES5

function myFunction(a) { return a * a; };
function mySecondFunction(a, b, c) {
    if (a < 0.5) {
        return b * c;
    } else {
        return b / c;
    }
}

// ES6
const myFunction = a => a * a;
const mySecondFunction = (a, b, c) => 
    a < 0.5 ? b * c : b / c;


// Binding
class T {
    constructor() {
        this.b = this.b.bind(this);
    }
    a = () => console.log(this)
    b() { console.log(this) }
}

Module 0

Destructuring

const obj = {
    a: 1,
    b: 2,
    nested: {
        c: 3,
    }
};

const { a, b, nested: { c } } = obj;
const { a, ...rest } = obj;
const thing = { a, b, ...rest };

const arr = [1, 2, 3, 4, 5];
const [a, b, c, ...rest] = arr;

Module 0

Promises

// ES5

const getSomething = (url, callback) => {
    // fake async
    const responses = API.get(url);
    if (response.statusCode === 200) {
        callback(null, response.data);
    } else {
        callback(new Error('Failed'), response.error);
    }
};

getSomething('http://google.com', function(err, data) { ... });

Module 0

Promises (cont)


// ES6

const getSomething = url => {
    // fake async
    return new Promise((accept, reject) => {
        const responses = API.get(url);
        if (response.statusCode === 200) {
            accept(response.data);
        } else {
            reject(response.error);
        }
    });
}

getSomething('http://google.com')
    .then(success)
    .catch(err);

Module 0

Promises (async await)


// ES6

const getSomething = async url => {
    // fake async
    const responses = API.get(url);
    if (response.statusCode === 200) {
        return response.data;
    }
    throw new Error(response.err);
}

async handler() {
    try {
        console.log(await getSomething('http://google.com'));
    } catch (e) {    
        console.error(e);
    }
}

React

Module 1

Fundamentals

Module 1

But first, a few considerations...

Module 1

Templating and state management

Module 1

Templating and state management

Cannot stress this enough.
Everything is JS

Module 1

First stop: Components

 

Two types of components: 

  1. "Class Components"
  2. "Functional Components"

 

 

Module 1

Module 1

Dumb Component





import React from 'react';

export default ({ counter, setCounter }) => (
    <div>
        <span>Count: {counter}</span>
        <button onClick={() => setCounter(counter + 1)}>+1</button>
    </div>
);

Module 1

Dumb Component

export default function() {
    var _component = function() {
        var _this;
        
        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }
    
        return _this;
    }

  Object(babel_runtime_helpers.createClass(_component, [{
    key: "render",
    value: function render() {
      var counter = this.props.counter;
      var setCounter = this.props.setCounter;
      return React.createElement(React.div, {
          children: React.createElement(...),
      });
    }
  }]);

  return _component;
}

Module 1

Stateful Component



import React, { Component } from 'react';
import CounterComponent from './counter';

export default class MyComponent extends Component {
    state = { counter: 0 }

    updateCounter = value => this.setState({ counter: value });
    
    render() {
        const { counter } = this.state;
        return (
            <CounterComponent 
                counter={counter} 
                setCounter={this.updateCounter} 
            />
        );
    }
}

Module 1

Stateful Component (don't)

import React, { Component } from 'react';
import CounterComponent from './counter';

export default class MyComponent extends Component {
    constructor() {
        super();
        this.state = { counter: 0 };
        this.updateCounter = this.updateCounter.bind(this);
    }

    updateCounter(value) { this.setState({ counter: value }); }
    
    render() {
        const { counter } = this.state;
        return (
            <CounterComponent 
                counter={counter} 
                setCounter={this.updateCounter} 
            />
        );
    }
}

Module 1

React Hooks


export default (props) => {
    const [counter, setCounter] = useState(0);
    useEffect(
        () => document.head.title = "Ready to count", 
        [],
    );
    useEffect(
        () => document.head.title = `Counted ${counter} times`, 
        [counter],
    );
    return (
        <div>
            <h2>Counter App</h2>
            <div>Counted {counter} times!</div>
            <button onClick={() => setCounter(counter + 1)}>Add one</button>
            <button onClick={() => setCounter(counter + 5)}>Add five</button>
            <button onClick={() => setCounter(counter - 1)}>Subtract one</button>
        </div>
    );
}

Module 1

State?


class MyComponent extends Component {
    ...
    render() {
        const { isEditing } = this.state;
        const { data, updateData } = this.props;
        ...
    }
}

class RootComponent extends Component {
    ...
    render() {
        return <MyComponent data={...} updateData={...} />
    }
}

Module 1

Lifecycle



class MyComponent extends Component {

    // on initial render
    componentWillMount() //deprecated
    componentDidMount()
    
    // props changes
    componentWillReceiveProps()
    componentShouldUpdate()
    componentWillUpdate()

    // state changes
    componentWillUpdate()

    // component is no longer being rendered
    componentWillUnmount()

    ...
}

React

Module 2

State / Data

Module 2

Two types of Data

 

  1. Properties             (props)
  2. Component State (state)

 

 

Module 2

Class Component



import React, { Component } from 'react';
import CounterComponent from './counter';

export default class MyComponent extends Component {
    state = { counter: 0 }

    updateCounter = value => this.setState({ counter: value });
    
    render() {
        const { counter } = this.state;
        const { firstName, lastName } = this.props;
        return (
            <CounterComponent 
                counter={counter} 
                name={`${firstName} ${lastName}`}
                setCounter={this.updateCounter} 
            />
        );
    }
}

Module 2

React Hooks


export default ({ name }) => {
    const [counter, setCounter] = useState(0);
    useEffect(
        () => document.head.title = "Ready to count", 
        [],
    );
    useEffect(
        () => document.head.title = `Counted ${counter} times`, 
        [counter],
    );
    return (
        <div>
            <h2>Counter App</h2>
            <h1>Hi, my name is {name}</h1>
            <div>Counted {counter} times!</div>
            <button onClick={() => setCounter(counter + 1)}>Add one</button>
            <button onClick={() => setCounter(counter + 5)}>Add five</button>
            <button onClick={() => setCounter(counter - 1)}>Subtract one</button>
        </div>
    );
}

React

Module 3

Global State

Module 3

Context API

Module 3

Redux

Module 3

React

Module 4

HTTP / Routing

HTTP?

Anything you like.

Module 4

Routing

Conditional.

Not Structural

Module 4

import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';

export default ({ isAdmin }) => (
    <Router>
        <Switch>
            <Route exact path="/" component={HomeComponent} />
            <Route path="/users" component={UsersLayout} />
        </Switch>
        <footer>
            <Route 
                exact 
                path="/admin" 
                render={() => <Link to="/">Home</Link>} 
            />
            {isAdmin && 
                <Route 
                    path="/not-an-admin" 
                    render={() => <Link to="/admin">Admin</Link>} 
                />
            }
        </footer>
    </Router>
);

Module 4

Module 4

Thank you!

 

React Intro

By Sabin Marcu

React Intro

  • 304