WE ARE THE JSLEAGUE
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:
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
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
Module 4
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