React - State Management

Ego Slide

f.strazzullo@extrategy.net

@TheStrazz86

https://github.com/francesco-strazzullo

https://medium.com/@TheStrazz86

https://slides.com/francescostrazzullo

Let's Talk about React...

A JavaScript library for building user interfaces

class HelloMessage extends React.Component {
  render() {
    return <div>Hello {this.props.name}!</div>;
  }
}

ReactDOM.render(<HelloMessage name="World" />, mountNode);

So Basically...it's not a framework

Features

Components

JSX

class HelloMessage extends React.Component {
  render() {
    return React.createElement(
      "div",
      null,
      "Hello ",
      this.props.name
    );
  }
}

ReactDOM.render(React.createElement(HelloMessage, { name: "World" }), mountNode);

Virtual Dom

Server Side Rendering

State

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {secondsElapsed: 0};
  }

  tick() {
    this.setState((prevState) => ({
      secondsElapsed: prevState.secondsElapsed + 1
    }));
  }

  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return (
      <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
    );
  }
}

ReactDOM.render(<Timer />, mountNode);

State Management

State management refers to the management of the state of one or more user interface controls such as text fields, OK buttons, radio buttons, etc. in a graphical user interface.

Wikipedia

First of all... DIY!

Why Not MVC?

We need one way of thinking

Flux

Application Architecture For Building User Interfaces

Action: an event fired in the system with the purpose to change its state

Dispatcher: an event bus to send actions into the system

Store: business logic objects. Just like the M in MVC

View: React Components

Why Not Flux?

We need one way of thinking

Redux is a predictable state container for JavaScript apps

You Might Not Need Redux

Principles

"Single source of truth"

The state of your whole application is stored in an object tree inside a single store.

"State is read-only"

The only way to mutate the state is to emit an action, an object describing what happened.

"Mutations are written as pure functions"

To specify how the state tree is transformed by actions, you write pure reducers.

Elements

Action: an event fired in the system with the purpose to change its state

var add = function(text) {
	return {
		actionType: "addTodo",
		text: text
	};
};

Reducer

function addTodo(state,text){
	var toReturn = Object.assign({},state,{
		todos:[...state.todos]
	});

	toReturn.todos.push(text);

	return toReturn;
};

Store

import { createStore } from 'redux';
import Reducers from 'src/Reducers';

let store = createStore(Reducers);

Container Components

Presentational Components

Middlewares

Why Redux?

One Way of Thinking (Really this time)

Serilizable State

No side-effect

No Technical Debt

Provide alternative UIs while reusing most of the business logic

Side Effects

(Async Actions)

onClick() {
    this.props.dispatch(actions.requestData())
    this.api.list().then(response => {
        this.props.dispatch(actions.requestDataSuccess(response.data))
    }).catch(error => {
        this.props.dispatch(actions.requestDataError(error))
    })
}

Middlewares

return store => dispatch => action {
    dispatch(action)

    switch (action.type) {
      case 'REQUEST_DATA':
         api.list().then(response => {
            dispatch(actions.requestDataSuccess(response.data))
         }).catch(error => {
            this.props.dispatch(actions.requestDataError(error))
         })
    }
  }

Redux Thunk

In computer programming, a thunk is a subroutine used to inject an additional calculation into another subroutine.

Wikipedia

function reqeustDataThunk() {
  return function (dispatch) {
    dispatch(requestData())
    return api.list().then(
      data => dispatch(requestDataSuccess(response.data)),
      error => dispatch(requestDataError(error))
    );
  };
}

store.dispatch(reqeustDataThunk());

Separation of concerns

A Saga is an independent component that reacts to domain events in a cross-aggregate, eventually consistent manner.

redux-saga is a library that aims to make side effects in Redux applications easier and better.

The mental model is that a saga is like a separate thread in your application that's solely responsible for side effects. 

function* fetch() {
   try {
      const data = yield call(api.list);
      yield put(actions.requestDataSuccess(data));
   } catch (e) {
      yield put(actions.requestDataError(e));
   }
}

function* mySaga() {
  yield takeLatest("REQUEST_DATA", fetch);
}

export default mySaga;

ES6 Generators

function *foo() {
    yield 1;
    yield 2;
    yield 3;
    yield 4;
    yield 5;
}

const it = foo();

console.log( it.next() ); // { value:1, done:false }
console.log( it.next() ); // { value:2, done:false }
console.log( it.next() ); // { value:3, done:false }
console.log( it.next() ); // { value:4, done:false }
console.log( it.next() ); // { value:5, done:false }
console.log( it.next() ); // { value:undefined, done:true }

MobX

MobX is a battle tested library that makes state management simple and scalable by transparently applying functional reactive programming.

Why Not Redux?

Boilerplate

No OOP Design

Reactive Programming

var a = b + c;

=B1+C1

const triangle = {
    base:2,
    height:3,
    color:'red',
    get area() {
        return (this.base * this.height) / 2
    }
};

const report = () => {
    console.log(triangle.area);
};

report();
const triangle = triangleFactory({
    base:2,
    height:3,
    color:'red'
});

const report = () => {
    console.log(triangle.area);
};

triangle.addChangeListener(report);

triangle.setBase(4);

MobX helps you observe your Model

const triangle = observable({
    base:2,
    height:3,
    color:'red',
    get area() {
        return (this.base * this.height) / 2
    }
});

const report = () => {
    console.log(triangle.area);
};

autorun(report);

//report()
triangle.base = 4;

//no report()
triangle.color = 'blue';

Core Concepts

Observable Models

Actions

Computed values

Reactions

view = f(state)
view=f(state)view = f(state)

Useful links

Thanks!

React State Management

By Francesco Strazzullo

React State Management

  • 1,762