react state management with redux and mobx

Post on 29-Jan-2018

841 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

React State Management with Redux and MobX

DARKO KUKOVEC @DarkoKukovec ANDREI ZVONIMIR CRNKOVIĆ @andreicek

INFINUM @infinumco

DARKO KUKOVEC JS Team Lead

@DarkoKukovec

ANDREI ZVONIMIR CRNKOVIĆ JS Emojineer @andreicek

We're an independent design & development agency.

Topic

Time

SCHEDULE

13:45-14:30 14:30-15:15 15:15-16:00

React setState React + Redux React + MobX

The Joy of Optimizing

Una Kravets (DigitalOcean)

Coffee.js? How I hacked my coffee machine using

JavaScript

Dominik Kundel (Twilio)

GraphQL: Data in modern times

Dotan Simha (The Guild)

01APP STATE

APP STATE

• Data • Which user is logged in? • Which todos did the user create?

• UI • Which todos is the user looking at (filter - all, complete, incomplete)

02STATE MANAGEMENT

STATE MANAGEMENT

• What should happen when some data changes?

• Does the UI need to be updated

• Does some other data depend on it?

• Does the app need to make an action (e.g. API call)?

03WHY DO WE NEED IT?

IMAGE GOES INSIDE THIS BOX DELETE BOX AFTER PLACING IMAGE

• Todos

• Title

• Status

• Active filter

• Number of todos

Handing an action in the app

Handing an action in the app

• The user checks a todo as complete

Handing an action in the app

• The user checks a todo as complete

• Mark the todo as complete

Handing an action in the app

• The user checks a todo as complete

• Mark the todo as complete

• Update the incomplete items count

Handing an action in the app

• The user checks a todo as complete

• Mark the todo as complete

• Update the incomplete items count

• What filter is active again?

Handing an action in the app

• The user checks a todo as complete

• Mark the todo as complete

• Update the incomplete items count

• What filter is active again?

• Do I need to update the list of todos?

• Add/remove item?

• Sort items?

• Should I show an empty state?

• Should I make an API call?

• Should I save the change into

localStorage?

Data Flow in JavaScript Applications - Ryan Christiani

04EXAMPLE PROJECT

EXAMPLE PROJECT

• Tech conference app

• Fetch talk list (async action)

• Favourite talks (simple sync action)

• Filter by location (filtering data from the state)

• To simplify • No routing • No forms • Not responsive • Only basic styling • Assumption: Browsers support Fetch API

• 70% of browsers do, polyfill available for the rest

EXAMPLE PROJECT - TECH STUFF

• create-react-app as the initial setup

• https://github.com/infinum/shift-2017

05BEFORE WE START...

COMPONENT TYPES

Container Presenter

Usually root components Inside of container components

No UI Only UI

State of children components Dumb component

Handle state changes "Data down, actions up"

06PREREQUISITES

PREREQUISITES

• A modern IDE (VS Code, Sublime Text, Atom, Webstorm or similar)

• Latest version of Chrome/Chromium for debugging

• Node.js 6 or 7

• npm 4 or yarn

07REACT + SETSTATE

REACT + SETSTATE

• No central state

• Every component contains its (and children?) state

• State changes are async! - 2nd argument is a callback

• Component is re-rendered unless shouldComponentUpdate() returns false

• Additional libs • react-addons-update

// Code time! // setState // Code used for setup: create-react-app app-setstate npm install --save react-addons-update

v1.0

* Mock data * Styles * Presenter components * Utils

v1.0

// Loading data

v1.0

// Container component state

v1.1

// Selectors

v1.2

FUNCTIONAL SETSTATE

• Since React 15?

• Will eventually replace the usage with objects as the first argument

class App extends Component { constructor(props) { super(props); this.state = {counter: 0}; }

increaseCounter() { this.setState({ counter: this.state.counter + 1 }); }

decreaseCounter() { this.setState((prevState, props) => { return {counter: prevState.counter + 1}; }); }

render() { // ... } }

SCALING SETSTATE

• A bad idea • One master component with app state • Some smaller independent containers

08MOBX VS REDUX

http:!//!!www.timqian.com/star-history/#mobxjs/mobx&reactjs/redux&facebook/flux&facebook/relay

ADVANTAGES

Easier to (unit) test

MobX Redux

Faster

Less boilerplate Smaller

Time travelMore flexible

Easier to debug?Simpler async actions

IN THE NUTSHELL...

https:!//twitter.com/phillip_webb/status/705909774001377280

USAGE

MobX Redux

mobx-react react-redux

Not React dependent Not React dependent

mobx-angular

Python

GWT

09REACT + REDUX

REACT + REDUX

• One central state

• Additional libs • redux • react-redux • redux-thunk

STORE Holds application state

ACTIONS Payloads of information that send data from your

application to your store

REDUCERS Specify how the application's state changes in

response to actions

import { createStore } from 'redux'

function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } }

let store = createStore(counter)

store.subscribe(() => console.log(store.getState()) )

store.dispatch({ type: 'INCREMENT' }) // 1 store.dispatch({ type: 'INCREMENT' }) // 2 store.dispatch({ type: 'DECREMENT' }) // 1

THE GIST

// Code time! // Redux // Code used for setup: create-react-app app-redux npm install --save redux react-redux redux-thunk

v2.0

* Mock data * Styles * Presenter components * Utils

v2.0

// Action names

v2.0

// Reducers

v2.2

// Selectors

v2.5

// Redux DevTools // https://chrome.google.com/webstore

https:!//chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=env2.6

SCALING REDUX

• Only one store!

• Multiple (nested) reducers, actions • Store data nesting === reducer nesting

• "reducers" folder, "actions" folder

• Folders based on functionality • e.g. "orders" contains a orders reducer, orders actions and all other related stuff

THINGS TO KEEP IN MIND

• NEVER mutate the state!

• Immutable.js

09REDUX HELPER LIBS

IMMUTABLE.JS

• https://github.com/facebook/immutable-js/

• List, Stack, Map, OrderedMap, Set, OrderedSet, Record

• Nested structures

REDUX FORM

• https://github.com/erikras/redux-form

• Uses Immutable.js

• Sync/async validations

• Wizard forms

REDUX - THE SOURCE CODE

https:!//twitter.com/bloodyowl/status/740228059538857984

10REACT + MOBX

REACT + MOBX

• One/multiple states

• Additional libs • mobx • mobx-react

Anything that can be derived from the application state, should be derived. Automatically.

- The philosophy behind MobX

OBSERVABLE Your state

e.g., list of TODOs

ACTION A function that changes the state

e.g., function called after the user clicks on the completed checkbox

COMPUTED PROPERTY A value derived from your state e.g., list of completed TODOs

OBSERVER Function (component?) that needs to be updated

on state change e.g., component showing a list of TODOs

STATE (OBSERVABLES)

COMPUTED PROPS

OBSERVERSACTION

UPDATES

UPDATESUPDATESCHANGES

THE GIST

import { observable, autorun } from 'mobx';

const store = observable({counter: 0});

autorun(() => console.log(store.counter); );

store.counter++; // 1 store.counter++; // 2 store.counter--; // 1

import { createStore } from 'redux'

function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } }

let store = createStore(counter)

store.subscribe(() => console.log(store.getState()) )

store.dispatch({ type: 'INCREMENT' }) // 1 store.dispatch({ type: 'INCREMENT' }) // 2 store.dispatch({ type: 'DECREMENT' }) // 1

THE GIST

import { observable, autorun } from 'mobx';

const store = observable({counter: 0});

autorun(() => console.log(store.counter); );

store.counter++; // 1 store.counter++; // 2 store.counter--; // 1

MobX Redux

DECORATORS JS proposed feature (Babel plugin)

TypeScript feature

import {observable, computed} from 'mobx';

class Todos { @observable list = []; users = observable([]);

@computed get complete() { return this.list.filter((todo) => todo.complete); }

incomplete: computed(() => { return this.list.filter((todo) => !todo.complete); }) }

// Code time! // MobX // Code used for setup: create-react-app app-mobx --scripts-version custom-react-scripts

npm install --save mobx mobx-react

v3.0

* Mock data * Styles * Presenter components * Utils

v3.0

// Loading data

v3.1

// Actions

v3.2

// Observers

v3.3

// Strict mode

v3.4

THINGS TO KEEP IN MIND

• use extendObservable to add properties to an object

• Wrapped objects - isArray(arr) or array.is(toJS(arr)) • Don't be afraid to use observers

• If done right: More observers → better performance

SCALING MOBX

• Your code can be object oriented!

• A list of best practices

• Strict mode, actions (transactions)

• Use helper libs

10MOBX HELPER LIBS

MOBX-REACT-DEVTOOLS

• Log actions & reactions

• Check dependencies for a react component

• Show update times

"STRUCTURE" LIBS Opinionated

MOBX-COLLECTION-STORE

• https://github.com/infinum/mobx-collection-store

• One collection, multiple model types

• Relationships between models

• mobx-jsonapi-store

• https://github.com/infinum/mobx-jsonapi-store

MOBX-STATE-TREE

• https://github.com/mobxjs/mobx-state-tree

• Made by MobX authors

• v1.0 release soon

• Supports snapshots, replay, JSON patches, etc.

• Supports time travel! • Compatible with Redux DevTools!

MOBX-REACT-FORM

• https://github.com/foxhound87/mobx-react-form

• Dedicated DevTools: https://github.com/foxhound87/mobx-react-form-devtools

REACT SETSTATE + MOBX

• You can still use it

• But, you can also do this…

import {observable} from 'mobx'; import {observer} from 'mobx-react'; import React, {Component} from 'react';

@observer export default class Foo extends Component { @observable state = { clickCount = 0; };

onClick: () => { this.state.clickCount++; // if you use setState it will stop being an observable! }

render() { return ( <button onClick={this.onClick}> { this.state.clickCount ? `Clicked ${this.state.clickCount} times!` : 'Click me!' } </button> ); } }

RESOURCES

• Redux • http://redux.js.org/ • https://egghead.io/courses/getting-started-with-redux • https://egghead.io/courses/building-react-applications-with-idiomatic-redux

• MobX • https://mobx.js.org/ • https://mobxjs.github.io/mobx/getting-started.html • https://egghead.io/courses/manage-complex-state-in-react-apps-with-mobx

Visit infinum.co or find us on social networks:

infinum.co infinumco infinumco infinum

Thank you! DARKO@INFINUM.CO @DARKOKUKOVEC

ANDREI@INFINUM.CO @ANDREICEK

top related