Slide 1

Slide 1 text

State management with MobX React Bangkok 3.0.0 - 24 June 2018

Slide 2

Slide 2 text

About Me ● Manatsawin Hanmongkolchai ● Junior Architect @ Wongnai ○ We do everything from infrastructure to frontend

Slide 3

Slide 3 text

Are you familiar with AngularJS?

Slide 4

Slide 4 text

How state management worked in AngularJS (~2013)

Slide 5

Slide 5 text

angular.controller('PageController', function($scope){ $scope.text = 'Hello world'; });

Slide 6

Slide 6 text

angular.controller('PageController', function($scope, $http){ $scope.data = []; $http.get('/_api/restaurants.json') .then(function(response){ $scope.data = response.data; }); });

Slide 7

Slide 7 text

angular.controller('PageController', function($scope, $http){ $scope.data = []; $http.get('/_api/restaurants.json') .then(function(response){ $scope.data = response.data; }); });

Slide 8

Slide 8 text

angular.controller('PageController', function($scope, $http){ $scope.data = []; $http.get('/_api/restaurants.json') .then(function(response){ $scope.data = response.data; }); });

Slide 9

Slide 9 text

angular.controller('PageController', function($scope, $http){ $scope.data = []; $http.get('/_api/restaurants.json') .then(function(response){ $scope.data = response.data; }); });

Slide 10

Slide 10 text

angular.controller('PageController', function($scope, $http){ $scope.data = []; $http.get('/_api/restaurants.json') .then(function(response){ $scope.data = response.data; }); });

Slide 11

Slide 11 text

How state management works with Redux Thunk

Slide 12

Slide 12 text

Reducer Action State Action creator New state

Slide 13

Slide 13 text

function fetchAction(){ return (dispatch) => { fetch('/_api/restaurants.json') .then((res) => res.json()) .then((data) => dispatch({ type: 'SET_RESTAURANT', data })); }; }

Slide 14

Slide 14 text

function reducer(state, action){ switch(action.type){ case 'SET_RESTAURANT': return Immutable.fromJS(action.data); default: return state || new Immutable.List(); } }

Slide 15

Slide 15 text

Redux works, but... ● It is quite boilerplatey ○ Some people just give up and just use it as key value store ● It has too many friends ○ react-redux, immutablejs, redux-immutable, redux-thunk/saga ○ Some people add reselect, redux-action ● It is hard to get new people onboard ○ Not only they have to learn React and Redux, they have to learn ALL of the above as well

Slide 16

Slide 16 text

Redux works, but... ● It has one store ○ 75% of wongnai.com page content is Redux state. Why we have to send you empty delivery coupons store when you'll never look at it? ○ We're working on it. Stay tuned on life.wongnai.com

Slide 17

Slide 17 text

Introducing MobX

Slide 18

Slide 18 text

MobX is a state management library

Slide 19

Slide 19 text

If you used AngularJS, you'll feel at home with MobX

Slide 20

Slide 20 text

...without Dependency Injection, Factory, Controller, etc.

Slide 21

Slide 21 text

MobX is a state management library

Slide 22

Slide 22 text

Let's take a look at MobX, compared to AngularJS

Slide 23

Slide 23 text

$scope.data = []; let scope = observable({ data: [] }); $http.get('/_api/restaurants.json') .then(function(response){ $scope.data = response.data; }); fetch('/_api/restaurants.json') .then((res) => res.json()) .then(action((data) => { scope.data = data; })); AngularJS MobX

Slide 24

Slide 24 text

$scope.data = []; let scope = observable({ data: [] }); $http.get('/_api/restaurants.json') .then(function(response){ $scope.data = response.data; }); fetch('/_api/restaurants.json') .then((res) => res.json()) .then(action((data) => { scope.data = data; })); AngularJS MobX Put this where you used to put $scope.$apply

Slide 25

Slide 25 text

observer((props) => { return
    {state.data.map((item, index) => (
  • {item.name}
  • ))}
; }); AngularJS MobX

Slide 26

Slide 26 text

observer((props) => { return
    {state.data.map((item, index) => (
  • {item.name}
  • ))}
; }); AngularJS MobX Wrap your view with this HOC

Slide 27

Slide 27 text

People often use decorators syntax (but it is optional)

Slide 28

Slide 28 text

Decorator syntax @observer function(props){ return
    {state.data.map((item, index) => (
  • {item.name}
  • ))}
; }

Slide 29

Slide 29 text

… is mostly the same as higher order function observer(function(props){ return
    {state.data.map((item, index) => (
  • {item.name}
  • ))}
; })

Slide 30

Slide 30 text

Free stuff with observer shouldComponentUpdate (Don't use PureComponent) Zero waste state update

Slide 31

Slide 31 text

@observer function(props){ return
    {state.data.map((item, index) => (
  • {item.name}
  • ))}
; }

Slide 32

Slide 32 text

@observer function(props){ return
    {state.data.map((item, index) => (
  • {item.name}
  • ))}
; } Only update when state.data is updated Not when state.otherField is updated

Slide 33

Slide 33 text

The more observer the better

Slide 34

Slide 34 text

let Item = observer((props) =>
  • {props.item.name}
  • ); let View = observer(() => (
      {state.data.map((item, index) => ( ))}
    ));

    Slide 35

    Slide 35 text

    let Item = observer((props) =>
  • {props.item.name}
  • ); let View = observer(() => (
      {state.data.map((item, index) => ( ))}
    )); Dereference things as late as possible

    Slide 36

    Slide 36 text

    let Item = observer((props) =>
  • {props.item.name}
  • ); let View = observer(() => (
      {state.data.map((item, index) => ( ))}
    )); Let MobX know that this component depends on item.name

    Slide 37

    Slide 37 text

    How do I layout my MobX store?

    Slide 38

    Slide 38 text

    You can do it any way you want! Here's what I use

    Slide 39

    Slide 39 text

    export default class Settings { @observable settings = { color1: '#82cef7', }; @observable saving = false; @observable error = null; @observable url = null; }

    Slide 40

    Slide 40 text

    export default class Settings { @observable settings = { color1: '#82cef7', }; @observable saving = false; @observable error = null; @observable url = null; } Just plain old OOP

    Slide 41

    Slide 41 text

    export default class Settings { async save(url){ let result = await this._post(url, { data: JSON.stringify(this.settings), }); runInAction('set url', () => { this.url = result.url; }); } }

    Slide 42

    Slide 42 text

    import BaseSettings from './base'; export default class AlertStore extends BaseSettings { @observable settings = { color1: '#82cef7', color2: '#ffffff', color3: '#ffffff', } // free save!! }

    Slide 43

    Slide 43 text

    There's a lot more to MobX mobx-state-tree, mobx-utils, custom observable etc.

    Slide 44

    Slide 44 text

    Wongnai is using MobX in new products (sorry can't talk about it yet)

    Slide 45

    Slide 45 text

    No content

    Slide 46

    Slide 46 text

    #WongnaiIsHiring careers.wongnai.com (หนานี้ใช NextJS)

    Slide 47

    Slide 47 text

    Thank you! I'll be hanging around or @awkwin on Twitter Question?