Skip to content

Migrating from AngularJS to React Measuring performance gains

guptag edited this page Aug 23, 2017 · 4 revisions

Redux

How it works

Flow

Core Concepts

Single State Tree(single source of truth)

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

Actions (state is only read-only)

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

Reducers (pure functions that update the state in immutable way)

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter
  } else {
    return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([{ text: action.text, completed: false }])
    case 'TOGGLE_TODO':
      return state.map(
        (todo, index) =>
          action.index === index
            ? { text: todo.text, completed: !todo.completed }
            : todo
      )
    default:
      return state
  }
}

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  }
}

Connected UI Components

React-Redux library provides a Higher order React component which automatically listens for store.subscribe(listener) events and triggers a render.

image

Pros

  • Redux pattern forces developers to think hard on the schema of the state tree.
  • Patterns will be consistent across the codebase (at the cost of verboseness).
  • State tree can be easily traced/monitored as actions are playing out in the UI.
  • No magic in the framework/library. Everything is explicit and easy to debug.
  • React/Redux is very fast compared to ng1.

Choke-Points in very large apps

  • Designing the state tree can be tricky in large apps (data normalization, avoiding depth).
  • Getting the right balance between Connected Components Vs Pure components.
  • New bottleneck would be "mapStateToProps".
  • Code would be very verbose with all the actions and state changes. One simple example might be that every ajax call will need to fire pending, updated, error/success states. This can quickly become cumbersome in larger apps. (may not be bad as the pattern would be the same across the app).
  • More towards functional programming, might seems alien to developers with Object Oriented background. image

Mobx

image

Core Concepts

Observable state, Computed Values

class TodoList {
    @observable todos = [];
    @computed get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length;
    }
}

Actions

@action
updateTodo() {
this.todos[0] = {
    title: "Take a walk",
    completed: false
};

Reactions

@observer
class TimerView extends React.Component {
    render() {
        return (<button onClick={this.onReset.bind(this)}>
                Seconds passed: {this.props.appState.timer}
            </button>);
    }

    onReset () {
        this.props.appState.resetTimer();
    }
};

OR

/* a function that observes the state */
autorun(function() {
    console.log("Completed %d of %d items",
        todoStore.completedCount,
        todoStore.todos.length
    );
});

Pros

  • No need to normalize the data and no hard rules on how to structure the data.
  • Programmers with Object Oriented background would prefer Mobx.
  • Porting services/view models from legacy ng1 application would be lot more straight forward.

Choke-Points in very large apps

  • Observable data structures for lists and map. Data must be converted to json (via .toJS()) to use with lodash's utility libraries.
  • May have a higher memory footprint in large apps.
  • Lots of promise chains can make it less performant. Every handler needs to wrapped with @action and reactions will be triggered for every promise chain handler.
  • Mobx synchronously triggers reactions whenever an observable property is changed, this can cause lot of performance bottlenecks. (enforcing strict mode right from the beginning helps with this issue).