React, Redux and Building
Applications that Scale
BY KRISTOF VAN MIEGEM
Co-Founder Codifly
Agenda
• Managing Application State
• Embracing Immutable Data Structures
• A Project Structure that Works
Managing Application State
With Redux
Example 1: Counter
Example 1: Counter
2 3
Example 2: Multiple Counters
Example 2: Multiple Counters
[ 1 ] [ 1, 4 ] [ 2, 4, 1 ]
Example 3: TodoMVC
Example 3: TodoMVC
{
todos: [
{ completed: true,
id: 0,
text: ‘Get a girfriend’ },
{ completed: true,
id: 1,
text: ‘Kiss her’ },
{ completed: false,
id: 2,
text: ‘Rule the world’ },
],
visibilityFilter: ‘SHOW_ALL’
}
State is Read-Only
The only way to change the state is to emit an
Action:
• A plain JavaScript that describes what
happened.
• Expresses an intent to change state
Example 1: Counter
{ type: ‘INC’ }
Example 2: Multiple Counters
Example 2: Multiple Counters
{ type: ‘INC’, counter: 0 }
{ type: ‘INC’, counter: 1 }
{ type: ‘INC’, counter: 2 }
{ type: ‘ADD_COUNTER’ }
Action Creators
function inc (counter) {
return { type: 'INC', counter };
}
function addCounter () {
return { type: 'ADD_COUNTER' };
}
State Changes are Made with Pure Functions
To specify how the state tree is transformed by
actions, you write reducers:
• Pure functions
• that take the previous state and an
action, and return the next state
reducer(state, action)
= reducer(state, action)
State Changes are Made with Pure Functions
Example: Counter
const counter = (state = 0, action) => {
switch (action.type) {
case 'INC':
return state + 1;
default:
return state;
}
};
Bringing it All Together: The Store
The store is responsible for:
• Containing the current state of the app
• Allowing state updates
• Notification of listeners
Store creation
let store = createStore(reducer)
Triggering changes: dispatching actions
store.dispatch(actionCreator(…))
Listening for state changes
store.subscribe(() =>
console.log(store.getState())
)
Bringing it All Together: The Store
Full Example
// Actions
const inc = () => ({ type: 'INC' });
const dec = () => ({ type: 'DEC' });
// Reducer
const counter = (state = 0, action) => {
switch (action.type) {
case ‘INC': return state + 1;
case ‘DEC': return state - 1;
default: return state;
}
};
Full Example
// View
class Counter extends React.Component {
render () {
return (
<div>
<h1>{this.props.value}</h1>
<button onClick={this.props.onIncrement}>
+
</button>
<button onClick={this.props.onDecrement}>
-
</button>
</div>
);
}
}
Full Example
// Store
const store = Redux.createStore(counter);
// Rendering
const render = () => {
ReactDOM.render(
<Counter
value={store.getState()}
onIncrement={() => store.dispatch(inc())}
onDecrement={() => store.dispatch(dec())}
/>,
document.getElementById('container')
);
};
render();
store.subscribe(render); https://jsfiddle.net/pxktc6pv/
Reselect
• Selectors get or compute data
• Selectors are composable
• Selectors are performant
Selectors
import { createSelector } from 'reselect'
const productsSelector =
state => state.productsInBasket
const vatPercentageSelector =
state => state.vatPercentage
const totalSelector = createSelector(
productsSelector,
vatPercentageSelector,
(products, vatPercentage) =>
products.reduce(
(acc, product) => acc + product.price, 0)
* (1 + vatPercentage)
)
Thunks
function inc () {
return (dispatch) => {
setTimeout(() => {
dispatch({ type: 'INC' });
}, 5000);
};
}
Embracing Immutable
Data Structures
For improved reasoning and performance
3 + 5 = 8
Numbers are Immutable
Arrays are Mutable
var a = [3];
a.push(5);
console.log(a);
Hypothetical Immutable Array
var a = [3];
a.push(5);
console.log(a);
var a = [3]i;
var a2
= a.push(4);
console.log(a);
console.log(a2);
Slide title https://facebook.github.io/immutable-js/
Immutable List
var a = [3]i;
var a2
= a.push(4);
console.log(a);
console.log(a2);
var l = List([3]);
var l2
= list.push(4);
console.log(l.toJS());
console.log(l2.toJS());
Updating Immutable Data
(1) Deep clone
(2) Perform changes
(3) Return result
Conceptually, the update process
Structural Sharing
1
2 3
4 6 75
8
9
Structural Sharing
1
2 3
4 6 75
8
9
Structural Sharing
1
2 3
4 6 75
8
9
10
Structural Sharing
1
2 3
4 6 75
8
9
10
11
Get and Set
const map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 4);
console.log(map2.count()); // 3
console.log(map1.get('b')); // 2
console.log(map2.get('b')); // 4
const list1 = Immutable.List([ 1, 2 , 3 ]);
const list2 = list1.set(1, 4);
console.log(list2.count()); // 3
console.log(list1.get(1)); // 2
console.log(list2.get(1)); // 4
Nested Data Structures
var nested1 =
Immutable.fromJS({ a: { b: [ 1, 2, 3 ] } });
var nested2 =
nested1.setIn(['a', 'b', 1], 4);
console.log(nested1.getIn(['a', 'b', 1])); // 2
console.log(
nested2.getIn(['a', ‘b’]).toJS()); // [ 1, 2, 3 ]
console.log(nested2.getIn(['a', 'b', 1])); // 4
A Project Structure
that Works
Best practices at Codifly
“EditorConfig helps developers define and
maintain consistent coding styles between
different editors and IDEs.”

http://editorconfig.org/
Editorconfig
Editorconfig
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
function gcd (a, b) {
if (a == 0)
return b;
else {
return gcd(b % a, a);
}
}
ESLint
function gcd (a, b) {
if (a == 0)
return b;
else {
return gcd(b % a, a);
}
}
ESLint
2:3 error Expected { after 'if' condition
2:9 error Expected '===' and instead saw '=='
4:8 warning Unexpected 'else' after 'return'
8:1 warning Block must not be padded by blank lines
function gcd (a, b) {
if (a === 0) {
return b;
}
return gcd(b % a, a);
}
ESLint
ESLint
• Static Code Analysis
• “Agenda Free”
• Pluggable Standalone Rules

http://eslint.org/docs/rules/
• Customization via .eslintrc
Bringing it All Together
/src
/actions

/constants
/components
/reducers
/selectors
index.html
index.js
.babelrc
.editorconfig
.eslintrc
.gitignore
package.json
webpack.config.babel.js
Let’s script!
Getting our hands dirty with Redux
Slide title https://lpnpz04lxl.codesandbox.io/
Let’s script!
• Go to https://codesandbox.io/s/23lp02ql9n
/src
/actions
counterActions.js
/components
ClickButton.js
Counter.js
/reducers
counterReducer.js

index.js
/selectors
counterSelectors.js
index.js
Ready,
Set,
Code!
Solution: https://codesandbox.io/s/xkmq2p11w
Looking for
a challenge?
We are hiring!
Check out: https://codifly.be/careers

2018 02-22 React, Redux & Building Applications that Scale | Redux

  • 1.
    React, Redux andBuilding Applications that Scale BY KRISTOF VAN MIEGEM Co-Founder Codifly
  • 2.
    Agenda • Managing ApplicationState • Embracing Immutable Data Structures • A Project Structure that Works
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
    Example 2: MultipleCounters [ 1 ] [ 1, 4 ] [ 2, 4, 1 ]
  • 8.
  • 9.
    Example 3: TodoMVC { todos:[ { completed: true, id: 0, text: ‘Get a girfriend’ }, { completed: true, id: 1, text: ‘Kiss her’ }, { completed: false, id: 2, text: ‘Rule the world’ }, ], visibilityFilter: ‘SHOW_ALL’ }
  • 10.
    State is Read-Only Theonly way to change the state is to emit an Action: • A plain JavaScript that describes what happened. • Expresses an intent to change state
  • 11.
  • 12.
  • 13.
    Example 2: MultipleCounters { type: ‘INC’, counter: 0 } { type: ‘INC’, counter: 1 } { type: ‘INC’, counter: 2 } { type: ‘ADD_COUNTER’ }
  • 14.
    Action Creators function inc(counter) { return { type: 'INC', counter }; } function addCounter () { return { type: 'ADD_COUNTER' }; }
  • 15.
    State Changes areMade with Pure Functions To specify how the state tree is transformed by actions, you write reducers: • Pure functions • that take the previous state and an action, and return the next state
  • 16.
    reducer(state, action) = reducer(state,action) State Changes are Made with Pure Functions
  • 17.
    Example: Counter const counter= (state = 0, action) => { switch (action.type) { case 'INC': return state + 1; default: return state; } };
  • 18.
    Bringing it AllTogether: The Store The store is responsible for: • Containing the current state of the app • Allowing state updates • Notification of listeners
  • 19.
    Store creation let store= createStore(reducer) Triggering changes: dispatching actions store.dispatch(actionCreator(…)) Listening for state changes store.subscribe(() => console.log(store.getState()) ) Bringing it All Together: The Store
  • 20.
    Full Example // Actions constinc = () => ({ type: 'INC' }); const dec = () => ({ type: 'DEC' }); // Reducer const counter = (state = 0, action) => { switch (action.type) { case ‘INC': return state + 1; case ‘DEC': return state - 1; default: return state; } };
  • 21.
    Full Example // View classCounter extends React.Component { render () { return ( <div> <h1>{this.props.value}</h1> <button onClick={this.props.onIncrement}> + </button> <button onClick={this.props.onDecrement}> - </button> </div> ); } }
  • 22.
    Full Example // Store conststore = Redux.createStore(counter); // Rendering const render = () => { ReactDOM.render( <Counter value={store.getState()} onIncrement={() => store.dispatch(inc())} onDecrement={() => store.dispatch(dec())} />, document.getElementById('container') ); }; render(); store.subscribe(render); https://jsfiddle.net/pxktc6pv/
  • 23.
    Reselect • Selectors getor compute data • Selectors are composable • Selectors are performant
  • 24.
    Selectors import { createSelector} from 'reselect' const productsSelector = state => state.productsInBasket const vatPercentageSelector = state => state.vatPercentage const totalSelector = createSelector( productsSelector, vatPercentageSelector, (products, vatPercentage) => products.reduce( (acc, product) => acc + product.price, 0) * (1 + vatPercentage) )
  • 25.
    Thunks function inc (){ return (dispatch) => { setTimeout(() => { dispatch({ type: 'INC' }); }, 5000); }; }
  • 26.
    Embracing Immutable Data Structures Forimproved reasoning and performance
  • 27.
    3 + 5= 8 Numbers are Immutable
  • 28.
    Arrays are Mutable vara = [3]; a.push(5); console.log(a);
  • 29.
    Hypothetical Immutable Array vara = [3]; a.push(5); console.log(a); var a = [3]i; var a2 = a.push(4); console.log(a); console.log(a2);
  • 30.
  • 31.
    Immutable List var a= [3]i; var a2 = a.push(4); console.log(a); console.log(a2); var l = List([3]); var l2 = list.push(4); console.log(l.toJS()); console.log(l2.toJS());
  • 32.
    Updating Immutable Data (1)Deep clone (2) Perform changes (3) Return result Conceptually, the update process
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
    Get and Set constmap1 = Immutable.Map({ a: 1, b: 2, c: 3 }); const map2 = map1.set('b', 4); console.log(map2.count()); // 3 console.log(map1.get('b')); // 2 console.log(map2.get('b')); // 4 const list1 = Immutable.List([ 1, 2 , 3 ]); const list2 = list1.set(1, 4); console.log(list2.count()); // 3 console.log(list1.get(1)); // 2 console.log(list2.get(1)); // 4
  • 38.
    Nested Data Structures varnested1 = Immutable.fromJS({ a: { b: [ 1, 2, 3 ] } }); var nested2 = nested1.setIn(['a', 'b', 1], 4); console.log(nested1.getIn(['a', 'b', 1])); // 2 console.log( nested2.getIn(['a', ‘b’]).toJS()); // [ 1, 2, 3 ] console.log(nested2.getIn(['a', 'b', 1])); // 4
  • 39.
    A Project Structure thatWorks Best practices at Codifly
  • 40.
    “EditorConfig helps developersdefine and maintain consistent coding styles between different editors and IDEs.”
 http://editorconfig.org/ Editorconfig
  • 41.
    Editorconfig root = true [*] indent_style= space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true
  • 42.
    function gcd (a,b) { if (a == 0) return b; else { return gcd(b % a, a); } } ESLint
  • 43.
    function gcd (a,b) { if (a == 0) return b; else { return gcd(b % a, a); } } ESLint 2:3 error Expected { after 'if' condition 2:9 error Expected '===' and instead saw '==' 4:8 warning Unexpected 'else' after 'return' 8:1 warning Block must not be padded by blank lines
  • 44.
    function gcd (a,b) { if (a === 0) { return b; } return gcd(b % a, a); } ESLint
  • 45.
    ESLint • Static CodeAnalysis • “Agenda Free” • Pluggable Standalone Rules
 http://eslint.org/docs/rules/ • Customization via .eslintrc
  • 46.
    Bringing it AllTogether /src /actions
 /constants /components /reducers /selectors index.html index.js .babelrc .editorconfig .eslintrc .gitignore package.json webpack.config.babel.js
  • 47.
    Let’s script! Getting ourhands dirty with Redux Slide title https://lpnpz04lxl.codesandbox.io/
  • 48.
    Let’s script! • Goto https://codesandbox.io/s/23lp02ql9n /src /actions counterActions.js /components ClickButton.js Counter.js /reducers counterReducer.js
 index.js /selectors counterSelectors.js index.js
  • 49.
  • 50.
    Looking for a challenge? Weare hiring! Check out: https://codifly.be/careers