September 29, 20175 min read
Mobx React — Best Practices

In this article I want to show you common best practices for using React with mobx. I will present them as rules. So whenever you come to a specific problem, try to solve it while sticking to these rules. This article requires that you have a basic understanding of stores in mobx. If not, read this first.

Need a quickstart?

I created a starter project, that implements the recommended practices.

The stores represent the ui state

Alway keep in mind that the stores represent your application’s ui state. That means, when you save your stores’ state to a file, close your program and relaunch it with the loaded state, you will have the same program and will see the same things, like you have seen before closing your program. Stores are not meant to be ‘local databases’. They also hold information about what button is visible, disabled, the current text of an input field, etc..

class SearchStore {
  @observable searchText;

  setSearchText = (searchText) => {
    this.searchText = searchText;

class SearchInput extends React.Component {
  handleInputChanged = (event) => {
    const { searchStore } = this.props;

  render() {
    const { searchStore } = this.props;
    return (

Separate your rest calls from the stores

Do not call your rest interface from within your stores. This makes them hard to test. Instead put these rest calls into extra classes and pass these instances to each store using the store’s constructor. When you write test, you can easily fake these api calls and pass your fake api instance to each store.

class TodoApi {
  fetchTodos = () => request.get("/todos");

class TodoStore {
  @observable todos = [];

  constructor(todoApi) {
    this.todoApi = todoApi;

  fetchTodos = async () => {
    const todos = await this.todoApi.fetchTodos();

    runInAction(() => {
      this.todos = todos;

// Then in your main
const todoApi = new TodoApi();
const todoStore = new TodoStore(todoApi);

Keep your business logic in stores

Don’t ever write business logic in your components. When you write your business logic in components, you have no chance to reuse it, your business logic gets spread over many components, what makes it hard to refactor or reuse the code. Write the business logic with methods in the stores and call these methods from your components.

Don’t create global store instances

Don’t ever create global store instances. You can not write any reasonable and reliable tests for your components. Instead use the Provider to inject your stores into your components props. Then in your tests you can easily mock these stores.

Mobx-React: provider and inject

const searchStore = new SearchStore();

const app = (
  <Provider searchStore={searchStore}>
    <SearchInput />

ReactDom.render(app, container);

Only the store is allowed to change its properties

Never change a store’s property directly in a component. Only the store is allowed to change its own properties. Always call a method from the store, that changes the store’s property. Otherwise your applications state (stores = application state) is updated from everywhere and you are slowly loosing control. That makes it very hard to debug.

Always annotate each component with @observer

Annotating each component with @observer allows each component to update on store prop changes. Otherwise the parent component annotated with @component needs to rerender, to update its child component. So less components need to be rerendered.

Use @computed

Let’s say you want your button disabled when a user doesn’t have the admin role and the application is not in “admin mode”. A single property like isAdmin in one store is not enough for this. You will need a computed property in your store.

class ApplicationStore {
  @observable loggedInUser;

  @observable isInAdminMode;

  isAdminButtonEnabled = () => {
    return this.loggedInUser.role === "admin" && this.isInAdminMode;

You don’t need react router

You don’t need react router. As I said before you want your stores to represent your application’s state. When you let react router handle part of your application state, you don’t let your stores represent the application state. So keep your current displayed view in a property in one of your stores. Then you have one component that just renders what the property says.

How to decouple state and ui

Try to favor controlled components over uncontrolled components

Always try to build controlled components. This makes testing components and the overall complexity of your components easy to handle.

I hope I could help you with these simple tips.