Evolving technologies
BY DAVID VANPACHTENBEKE
Web and Mobile engineer at Codifly
About me
• Age 26, living in Merelbeke
• Married to Femke
• Graduated Industrial Engineer Informatics
at UGent in 2014
• Worked 2,5 years as a back end Java
developer
• Started working for Codifly February
2017

=> Became front end Javascript
developer
• Favorite technology: React Native
• React 16.X
• Babel 7
• Webpack 4
Agenda
React 16.X
Fragments, lifecycle methods, Context API 

and much more
New render() Return Types
• React Element
• null, Boolean
• String, Number
• Portals
• Arrays, Fragments
Render Strings
import React, { Component }
from 'react';
class Quote extends Component {
render () {
return (
<span>

Something truly inspiring

</span>
);
}
}
import React, { Component }
from 'react';
class Quote extends Component {
render () {
return "Something truly inspiring";
}
}
Render Arrays
import React, { Component }
from 'react';
class Mother extends Component {
render () {
return (
<div>
<span>David</span>
Jovi
<span>Arvid</span>
</div>
);
}
}
import React, { Component }
from 'react';
class Mother extends Component {
render () {
return [
<span key="david">David</span>,
"Jovi",
<span key="arvid">Arvid</span>,
];
}
}
Render Fragments
import React, { Component }
from 'react';
class Mother extends Component {
render () {
return [
<span key="david">David</span>,
"Jovi",
<span key="arvid">Arvid</span>,
];
}
}
import React, { Component }
from 'react';
class Mother extends Component {
render () {
return (
<React.Fragment>
<span>David</span>
Jovi
<span>Arvid</span>
</React.Fragment>
);
}
}
The Old Component Lifecycle
constructor
willMount
render
didMount
willReceiveProps
shouldUpdate
willUpdate
render
didUpdate
willUnmount
Props change
setState()
unmount
returned false
Deprecations
constructor
willMount
render
didMount
willReceiveProps
shouldUpdate
willUpdate
render
didUpdate
willUnmount
Props change
setState()
unmount
returned false
Migration
constructor
willMount
render
didMount
willReceiveProps
shouldUpdate
willUpdate
render
didUpdate
willUnmount
Props change
setState()
unmount
returned false
UNSAFE_
Strict Mode
import React, { StrictMode } from 'react';
...

ReactDOM.render(
<StrictMode>
<HelloWrapper name="World" />
</StrictMode>,
document.getElementById('container')
);
The New Component Lifecycle
constructor
render
getDerivedState

FromProps
didMount
getDerived

StateFromProps
shouldUpdate
render
getSnapshot

BeforeUpdate
didUpdate
willUnmount
Props change
setState()
unmount
returned false
"getDerivedStateFromProps is invoked after a
component is instantiated as well as when it
receives new props. It should return an object to
update state, or null to indicate that the new
props do not require any state updates."
New Lifecycle Method:
getDerivedStateFromProps()

static
getDerivedStateFromProps

(nextProps, prevState)
Example: https://jsfiddle.net/ywacrauq/1/
"getSnapshotBeforeUpdate() is invoked right before the most
recently rendered output is committed to e.g. the DOM. It
enables your component to capture current values (e.g. scroll
position) before they are potentially changed. Any value
returned by this lifecycle will be passed as a parameter
to componentDidUpdate()."
New Lifecycle Hooks
getSnapshotBeforeUpdate

(prevProps, prevState)


componentDidUpdate

(prevProps, prevState, snapshot)
Example: https://jsfiddle.net/xpj1hk4f/1/
“Context provides a way to pass data through the
component tree without having to pass props
down manually at every level.”
Context
• react-intl: <IntlProvider> and injectIntl()
• react-redux: <Provider> and connect()
• react-router: <Router> and withRouter()
• …
Case Study: Redux’ Provider
import React, { Component } from 'react';
import { Provider, connect } from 'react-redux';
ReactDOM.render(
<Provider store={store}><AppRoot /></Provider>, // places the store on the context
rootEl);
...
class _SomeSubComponent extends Component {
constructor(props) {
super(props);
console.log(props); // gets the store from context, and add store-things to props
}
}
const SomeSubComponent = connect(…)(_SomeSubComponent)
Example: a ThemeContext
import React, { Component } from 'react';
const ThemeContext = React.createContext(); // An object { Provider, Consumer }
ReactDOM.render(
<ThemeContext.Provider value='dark'>
<App />
</ThemeContext.Provider>,
document.getElementById('container'));
...
const Button = (props) => (
<ThemeContext.Consumer>
{value => <button className={`btn-${value}`} {...props} />}
</ThemeContext.Consumer>
);
Full Version: https://jsfiddle.net/oh5dyzsp/1/
“… there are a few cases where you need to 

imperatively modify a child outside of the
typical dataflow. The child to be modified could
be an instance of a React component, or it could
be a DOM element.”
Refs
Approach 1: String Refs
class InputApp extends React.Component {
componentDidMount() {
const inputEl = this.refs.inputEl;
inputEl.focus();
}
render() {
return <input value="" ref="inputEl" />;
}
}
Approach 1: String Refs
class InputApp extends React.Component {
componentDidMount() {
const inputEl = this.refs.inputEl;
inputEl.focus();
}
render() {
return <input value="" ref="inputEl" />;
}
}
Approach 2: Callback Refs
class InputApp extends React.Component {
componentDidMount() {
const inputEl = this.inputEl;
inputEl.focus();
}
render() {
return
<input value=""
ref={(el) => { this.inputEl = el; }} />;
}
}
Approach 3: Object Refs (New!)
class InputApp extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
const inputEl = this.inputRef.current;
inputEl.focus();
}
render() {
return <input value="" ref={this.inputRef} />;
}
}
forwardRef() (1/2)
class OurInput extends React.Component {
render() {
return <input
{...this.props}
className="our-input"
ref={(x) => { this.inputEl = x; }} />;
}
}
...
const OurInput = React.forwardRef(
(props, ref) => (
<input
{...props}
className="our-input"
ref={ref} />));
...
forwardRef() (2/2)
...
class InputApp extends React.Component {
componentDidMount() {
const inputEl =
this.ourInputEl.inputEl;
inputEl.focus();
}
render() {
return <OurInput
value=""
ref={
(x) => { this.ourInputEl = x; }} />;
}
}
...
class InputApp extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
const inputEl = this.inputRef.current;
inputEl.focus();
}
render() {
return <OurInput
value=""

ref={this.inputRef} />;
}
}
“Error boundaries are React components
that catch JavaScript errors anywhere in their
child component tree, log those errors, and
display a fallback UI instead of the component
tree that crashed. Error boundaries catch errors
during rendering, in lifecycle methods, and in
constructors of the whole tree below them.”
Error Boundaries
Defining Error Boundaries:
componentDidCatch()
import React, { Component } from 'react';
class OurErrorBoundary extends Component {
...
componentDidCatch(error, { componentStack }) {
// error: the error that has been thrown.
// componentStack: information about the component stack when the error occurred.
this.setState({ kaboom: true });
}
render() {
if (this.state.kaboom) {
return ... // render error UI
}
... // render normal UI
}
}
Full Version: https://jsfiddle.net/ub42zaqv/2/
• New core: React Fiber
• Custom DOM Attributes
• Smaller footprint
• No more react-addons
• MIT-license
• …
Gimme More
Slide title https://reactjs.org/blog/all.html
Babel 7
Optional Chaining Operator
o1?.o2?.f?.() // ± o1 && o1.o2 && o1.o2.f && o1.o2.f()
Optional Catch Binding
try { ... } catch { ... }
Numeric Separators
3_000_000_000.000_003

0b1010_0001_1000_0101
New Language Features
Pipeline Operator
x |> f1 |> f2 // f2(f1(x))
Throw Expressions
() => throw 'Boom!'
Nullish Coalescing Operator
fee ?? 15
New Language Features
New Language Features:

React Fragments, Revisited
import React, { Component }
from 'react';
class Mother extends Component {
render () {
return (
<React.Fragment>
<span>David</span>
Jovi
<span>Arvid</span>
</React.Fragment>
);
}
}
import React, { Component }
from 'react';
class Mother extends Component {
render () {
return (
<>
<span>David</span>
Jovi
<span>Arvid</span>
</>
);
}
}
• Type Safety & Auto completion
• Explicit choice: Flow or TypeScript
TypeScript
More Changes
• Object Rest Spread
• Class Properties
• Dynamic Import
• Decorators
• ...
Stage 2 => Stage 3 / Supports non-string keys
Stage 2 => Stage 3
Stage 2 => Stage 3
Stage 1 => Stage 2 / Still WIP
...
Intermezzo:

Class Properties
Initializing State
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: this.props.initialCount
};
}
...
}
class Counter extends Component {
state = {
count: this.props.initialCount
}
...
}
Static fields (e.g., propTypes)
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: this.props.initialCount
};
}
...
}
Counter.propTypes = {
initialCount: 0
};
class Counter extends Component {
static propTypes = {
initialCount: 0,
};
state = {
count: this.props.initialCount
}
...
}
Bounded Methods
class Counter extends Component {
constructor(props) {
super(props);
this.onClick = ::this.onClick;
this.state = {
count: this.props.initialCount
};
}
onClick() {
this.setState({
count: this.state.count + 1 });
}
...
}
Counter.propTypes = {
initialCount: 0
};
class Counter extends Component {
static propTypes = {
initialCount: 0,
};
state = {
count: this.props.initialCount
}
onClick = () => {
this.setState({
count: this.state.count + 1 });
}
...
}
Bounded Methods
class Counter extends Component {
constructor(props) {
super(props);
this.onClick = ::this.onClick;
this.state = {
count: this.props.initialCount
};
}
onClick() {
this.setState({
count: this.state.count + 1 });
}
...
}
Counter.propTypes = {
initialCount: 0
};
class Counter extends Component {
static propTypes = {
initialCount: 0,
};
state = {
count: this.props.initialCount
}
onClick = () => {
this.setState({
count: this.state.count + 1 });
}
...
}
class Counter extends Component {
constructor(props) {
super(props);
this.onClick = () => {
this.setState({
count: this.state.count + 1 });
}
this.state = {
count: this.props.initialCount
};
}
...
}
Counter.propTypes = {
initialCount: 0
};
Solution: Autobind
class Counter extends Component {
constructor(props) {
super(props);
this.onClick = ::this.onClick;
this.state = {
count: this.props.initialCount
};
}
onClick() {
this.setState({
count: this.state.count + 1 });
}
...
}
Counter.propTypes = {
initialCount: 0
};
import autobind 

from 'autobind-decorator';



class Counter extends Component {
static propTypes = {
initialCount: 0,
};
state = {
count: this.props.initialCount
}
@autobind onClick() {
this.setState({
count: this.state.count + 1 });
}
...
}
Webpack 4
Pack to the future!
Plugins
plugins.push(new DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(NODE_ENV) },
}))
plugins.push(new NamedModuleErrorsPlugin())
plugins.push(new NoEmitOnErrorsPlugin())
plugins.push(new ModuleConcatenationPlugin())
plugins.push(new CommonChunksPlugin())
optimization: {
concatenateModules: true,
namedModules: true,
noEmitOnErrors: true,
splitChunks,
}
Code splitting
import React from 'react';
import { Route, Switch }
from 'react-router-dom';
// Pages
import Home from './pages/home';
import SomePage from './pages/somePage';
export default () => (
<Switch>
<Route path="/" component={Home} />
<Route path="/some"
component={SomePage} />
</Switch>
);
// File used to export the page itself
import React from 'react';
import Async from 'react-loabable';
import Spinner from '../../components';
import HomePage from './Home';
export default Async({
loader: () => import('./Home'),
loading: Spinner,
});
Optimizations
• Mode
• First class supports
• Defaults
• Optimization property
Future
• CSS & HTML module types
• ZERO config platform
• Multicore
• Persistent caching




Demo Time!
Wij zoeken
nog toffe
collega’s!

2018 05-16 Evolving Technologies: React, Babel & Webpack

  • 1.
    Evolving technologies BY DAVIDVANPACHTENBEKE Web and Mobile engineer at Codifly
  • 2.
    About me • Age26, living in Merelbeke • Married to Femke • Graduated Industrial Engineer Informatics at UGent in 2014 • Worked 2,5 years as a back end Java developer • Started working for Codifly February 2017
 => Became front end Javascript developer • Favorite technology: React Native
  • 3.
    • React 16.X •Babel 7 • Webpack 4 Agenda
  • 4.
    React 16.X Fragments, lifecyclemethods, Context API 
 and much more
  • 5.
    New render() ReturnTypes • React Element • null, Boolean • String, Number • Portals • Arrays, Fragments
  • 6.
    Render Strings import React,{ Component } from 'react'; class Quote extends Component { render () { return ( <span>
 Something truly inspiring
 </span> ); } } import React, { Component } from 'react'; class Quote extends Component { render () { return "Something truly inspiring"; } }
  • 7.
    Render Arrays import React,{ Component } from 'react'; class Mother extends Component { render () { return ( <div> <span>David</span> Jovi <span>Arvid</span> </div> ); } } import React, { Component } from 'react'; class Mother extends Component { render () { return [ <span key="david">David</span>, "Jovi", <span key="arvid">Arvid</span>, ]; } }
  • 8.
    Render Fragments import React,{ Component } from 'react'; class Mother extends Component { render () { return [ <span key="david">David</span>, "Jovi", <span key="arvid">Arvid</span>, ]; } } import React, { Component } from 'react'; class Mother extends Component { render () { return ( <React.Fragment> <span>David</span> Jovi <span>Arvid</span> </React.Fragment> ); } }
  • 9.
    The Old ComponentLifecycle constructor willMount render didMount willReceiveProps shouldUpdate willUpdate render didUpdate willUnmount Props change setState() unmount returned false
  • 10.
  • 11.
  • 12.
    Strict Mode import React,{ StrictMode } from 'react'; ...
 ReactDOM.render( <StrictMode> <HelloWrapper name="World" /> </StrictMode>, document.getElementById('container') );
  • 13.
    The New ComponentLifecycle constructor render getDerivedState
 FromProps didMount getDerived
 StateFromProps shouldUpdate render getSnapshot
 BeforeUpdate didUpdate willUnmount Props change setState() unmount returned false
  • 14.
    "getDerivedStateFromProps is invoked aftera component is instantiated as well as when it receives new props. It should return an object to update state, or null to indicate that the new props do not require any state updates." New Lifecycle Method: getDerivedStateFromProps()
 static getDerivedStateFromProps
 (nextProps, prevState) Example: https://jsfiddle.net/ywacrauq/1/
  • 15.
    "getSnapshotBeforeUpdate() is invoked rightbefore the most recently rendered output is committed to e.g. the DOM. It enables your component to capture current values (e.g. scroll position) before they are potentially changed. Any value returned by this lifecycle will be passed as a parameter to componentDidUpdate()." New Lifecycle Hooks getSnapshotBeforeUpdate
 (prevProps, prevState)

 componentDidUpdate
 (prevProps, prevState, snapshot) Example: https://jsfiddle.net/xpj1hk4f/1/
  • 16.
    “Context provides away to pass data through the component tree without having to pass props down manually at every level.” Context • react-intl: <IntlProvider> and injectIntl() • react-redux: <Provider> and connect() • react-router: <Router> and withRouter() • …
  • 17.
    Case Study: Redux’Provider import React, { Component } from 'react'; import { Provider, connect } from 'react-redux'; ReactDOM.render( <Provider store={store}><AppRoot /></Provider>, // places the store on the context rootEl); ... class _SomeSubComponent extends Component { constructor(props) { super(props); console.log(props); // gets the store from context, and add store-things to props } } const SomeSubComponent = connect(…)(_SomeSubComponent)
  • 18.
    Example: a ThemeContext importReact, { Component } from 'react'; const ThemeContext = React.createContext(); // An object { Provider, Consumer } ReactDOM.render( <ThemeContext.Provider value='dark'> <App /> </ThemeContext.Provider>, document.getElementById('container')); ... const Button = (props) => ( <ThemeContext.Consumer> {value => <button className={`btn-${value}`} {...props} />} </ThemeContext.Consumer> ); Full Version: https://jsfiddle.net/oh5dyzsp/1/
  • 19.
    “… there area few cases where you need to 
 imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element.” Refs
  • 20.
    Approach 1: StringRefs class InputApp extends React.Component { componentDidMount() { const inputEl = this.refs.inputEl; inputEl.focus(); } render() { return <input value="" ref="inputEl" />; } }
  • 21.
    Approach 1: StringRefs class InputApp extends React.Component { componentDidMount() { const inputEl = this.refs.inputEl; inputEl.focus(); } render() { return <input value="" ref="inputEl" />; } }
  • 22.
    Approach 2: CallbackRefs class InputApp extends React.Component { componentDidMount() { const inputEl = this.inputEl; inputEl.focus(); } render() { return <input value="" ref={(el) => { this.inputEl = el; }} />; } }
  • 23.
    Approach 3: ObjectRefs (New!) class InputApp extends React.Component { constructor(props) { super(props); this.inputRef = React.createRef(); } componentDidMount() { const inputEl = this.inputRef.current; inputEl.focus(); } render() { return <input value="" ref={this.inputRef} />; } }
  • 24.
    forwardRef() (1/2) class OurInputextends React.Component { render() { return <input {...this.props} className="our-input" ref={(x) => { this.inputEl = x; }} />; } } ... const OurInput = React.forwardRef( (props, ref) => ( <input {...props} className="our-input" ref={ref} />)); ...
  • 25.
    forwardRef() (2/2) ... class InputAppextends React.Component { componentDidMount() { const inputEl = this.ourInputEl.inputEl; inputEl.focus(); } render() { return <OurInput value="" ref={ (x) => { this.ourInputEl = x; }} />; } } ... class InputApp extends React.Component { constructor(props) { super(props); this.inputRef = React.createRef(); } componentDidMount() { const inputEl = this.inputRef.current; inputEl.focus(); } render() { return <OurInput value=""
 ref={this.inputRef} />; } }
  • 26.
    “Error boundaries areReact components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.” Error Boundaries
  • 27.
    Defining Error Boundaries: componentDidCatch() importReact, { Component } from 'react'; class OurErrorBoundary extends Component { ... componentDidCatch(error, { componentStack }) { // error: the error that has been thrown. // componentStack: information about the component stack when the error occurred. this.setState({ kaboom: true }); } render() { if (this.state.kaboom) { return ... // render error UI } ... // render normal UI } } Full Version: https://jsfiddle.net/ub42zaqv/2/
  • 28.
    • New core:React Fiber • Custom DOM Attributes • Smaller footprint • No more react-addons • MIT-license • … Gimme More
  • 29.
  • 30.
  • 31.
    Optional Chaining Operator o1?.o2?.f?.()// ± o1 && o1.o2 && o1.o2.f && o1.o2.f() Optional Catch Binding try { ... } catch { ... } Numeric Separators 3_000_000_000.000_003
 0b1010_0001_1000_0101 New Language Features
  • 32.
    Pipeline Operator x |>f1 |> f2 // f2(f1(x)) Throw Expressions () => throw 'Boom!' Nullish Coalescing Operator fee ?? 15 New Language Features
  • 33.
    New Language Features:
 ReactFragments, Revisited import React, { Component } from 'react'; class Mother extends Component { render () { return ( <React.Fragment> <span>David</span> Jovi <span>Arvid</span> </React.Fragment> ); } } import React, { Component } from 'react'; class Mother extends Component { render () { return ( <> <span>David</span> Jovi <span>Arvid</span> </> ); } }
  • 34.
    • Type Safety& Auto completion • Explicit choice: Flow or TypeScript TypeScript
  • 35.
    More Changes • ObjectRest Spread • Class Properties • Dynamic Import • Decorators • ... Stage 2 => Stage 3 / Supports non-string keys Stage 2 => Stage 3 Stage 2 => Stage 3 Stage 1 => Stage 2 / Still WIP ...
  • 36.
  • 37.
    Initializing State class Counterextends Component { constructor(props) { super(props); this.state = { count: this.props.initialCount }; } ... } class Counter extends Component { state = { count: this.props.initialCount } ... }
  • 38.
    Static fields (e.g.,propTypes) class Counter extends Component { constructor(props) { super(props); this.state = { count: this.props.initialCount }; } ... } Counter.propTypes = { initialCount: 0 }; class Counter extends Component { static propTypes = { initialCount: 0, }; state = { count: this.props.initialCount } ... }
  • 39.
    Bounded Methods class Counterextends Component { constructor(props) { super(props); this.onClick = ::this.onClick; this.state = { count: this.props.initialCount }; } onClick() { this.setState({ count: this.state.count + 1 }); } ... } Counter.propTypes = { initialCount: 0 }; class Counter extends Component { static propTypes = { initialCount: 0, }; state = { count: this.props.initialCount } onClick = () => { this.setState({ count: this.state.count + 1 }); } ... }
  • 40.
    Bounded Methods class Counterextends Component { constructor(props) { super(props); this.onClick = ::this.onClick; this.state = { count: this.props.initialCount }; } onClick() { this.setState({ count: this.state.count + 1 }); } ... } Counter.propTypes = { initialCount: 0 }; class Counter extends Component { static propTypes = { initialCount: 0, }; state = { count: this.props.initialCount } onClick = () => { this.setState({ count: this.state.count + 1 }); } ... } class Counter extends Component { constructor(props) { super(props); this.onClick = () => { this.setState({ count: this.state.count + 1 }); } this.state = { count: this.props.initialCount }; } ... } Counter.propTypes = { initialCount: 0 };
  • 41.
    Solution: Autobind class Counterextends Component { constructor(props) { super(props); this.onClick = ::this.onClick; this.state = { count: this.props.initialCount }; } onClick() { this.setState({ count: this.state.count + 1 }); } ... } Counter.propTypes = { initialCount: 0 }; import autobind 
 from 'autobind-decorator';
 
 class Counter extends Component { static propTypes = { initialCount: 0, }; state = { count: this.props.initialCount } @autobind onClick() { this.setState({ count: this.state.count + 1 }); } ... }
  • 42.
    Webpack 4 Pack tothe future!
  • 43.
    Plugins plugins.push(new DefinePlugin({ 'process.env': { NODE_ENV:JSON.stringify(NODE_ENV) }, })) plugins.push(new NamedModuleErrorsPlugin()) plugins.push(new NoEmitOnErrorsPlugin()) plugins.push(new ModuleConcatenationPlugin()) plugins.push(new CommonChunksPlugin()) optimization: { concatenateModules: true, namedModules: true, noEmitOnErrors: true, splitChunks, }
  • 44.
    Code splitting import Reactfrom 'react'; import { Route, Switch } from 'react-router-dom'; // Pages import Home from './pages/home'; import SomePage from './pages/somePage'; export default () => ( <Switch> <Route path="/" component={Home} /> <Route path="/some" component={SomePage} /> </Switch> ); // File used to export the page itself import React from 'react'; import Async from 'react-loabable'; import Spinner from '../../components'; import HomePage from './Home'; export default Async({ loader: () => import('./Home'), loading: Spinner, });
  • 45.
    Optimizations • Mode • Firstclass supports • Defaults • Optimization property
  • 46.
    Future • CSS &HTML module types • ZERO config platform • Multicore • Persistent caching
  • 47.
  • 48.