Member preview

Todo App with Mobx-State-Tree and ES7 Decorators in React

Want to understand how to make an app with Mobx-State-Tree models and React components? Just take a look at this Todo App.

Start by creating app and set up of Decorators.

create-react-app mst-todo
cd mst-todo
yarn eject
yarn add babel-plugin-transform-decorators-legacy --dev

Configure package.json by adding

Add Mobx-State-Tree and devtools.

yarn add mobx mobx-react mobx-state-tree mobx-devtools-mst

Create jsconfig.json in root directory to avoid highlighting of decorators

Our App should be made of form, list and maybe simple text, which would show us a total number of todos.

In this case start with making MST models and React components.

/src
/components
Input.jsx
Todo.jsx
TodoList.jsx
/models
Todo.js
TodoList.js
TodoStore.js

First make a model for our store, which will be the list of todos.

In .views we can use get before our method to access it later without parenthesis e.g {this.props.total}

Then present the store to our app in index.js

Now we are able to make models for our Todo and TodoList.

Thanks to MobX, we do not have to copy state in actions like with Redux.

After creating the models we can make our components and use decorators for observers and also to get the store with inject. To use it like this, our component has to be stateful.

Start with the form, which will take our todos and push them to the store.

Next make Todo.jsx component, which will display todo’s name, will be completed on click (line-through) and removed on button’s click (if todo is “completed” as we wrote in Todo.js action).

Todo.jsx can be stateless component and will get props from TodoList.jsx. In this case we have to use export default observer(Todo), because decorators are not allowed.

TodoList.jsx will list every todo, which will exist in the store.

In CSS, e.g App.css add .completed { text-decoration: line-through; }

Finally, create App.js and run app with yarn start

If you are curious how it would look without decorators, we could pass store with props<Input todostore={todostore} /> but then it could go too deep. Another way of doing it would be with React Context.