Structuring a React Native + MobX Application the Right Way

Bhavish Hak
The GeekyAnts Blog
Published in
6 min readAug 29, 2017

--

I am going to discuss the structure of a React Native application in a way that I think is intuitive and overcomes many problem people face while building a React Native App.

When MobX works and shows its magic, you are like ‘meh’. But when it doesn’t, you have no idea what went wrong or why isn’t that particular element re-rendering, you just pray to God and hope that some hack works.

This article contains few tips on how to structure your app to ease the development process.

How do I structure my app?

• There are many ways to structure your MobX app, keep all stores in one folder or keep each store with the respective component etc.
• Unlike Redux where you have only one store to keep all your data, here you can have as many stores as you like. But how much is too much? Or is there anything like too much in Mobx’s dictionary?

You can take a look into this repo to see how it works.

So the structure looks like this:

  • First we make use of storybooks as it helps in our UI development. You should use it too as it separates your app’s business logic from the UI development.
    • So we have a storybooks folder which contains components and screens folders.
    screens are the presentational components for each of your apps screens.
    components are all the reusable components in your app (like a button , common header etc).
    • So these two folders contains pure UI React components which works purely on props.

The thought behind it is that your UI developers can independently and in parallel develop the UI part of your app and it’s easier to test your UI separately.

  • Then inside the src folder we’ll keep all the app logic.
    • First there is a boot folder which will initialize your app so you can include any number of functions here as you like. I would suggest to have a look into this folder from the repo.
    • So you can initialize all your functions for push notifications, loading assets for your app, having socket listener functions, etc. These functions will have access to your Mobx store too, so it’s pretty straight forward to make changes.
  • Inside src there is another folder called container which contains the screens which we define inside storybooks. Here you can wrap your screens component with all the things you need. Like @inject @observer etc. so that the container will have access to your Mobx store and you can pass down the values needed by the screen through props.
    Also all the callback functions will stay in this container for that particular screen. So you can call the actions for a particular callback.
  • Also inside src folder there will be a stores folder which further contains two subfolders, namely domain and view (UI store). You can read more about them in the Mobx docs.
  • We have a models folder which contains the model/schema for your Mobx store, so that you can store all your Mobx data using these models. This models folder works like a schema for your Mobx store. This streamlines your Mobx store and you can reuse these models as you see fit. I’ll explain the use of these models further in the article below.
  • Lastly there is the services folder where you write all your functions that handle your backend data. All the functions in this folder will have one basic task i.e based on the arguments perform an async operation and return the data or error.
    So all these async functions calls will happen only from our domain store, so that the data returned by these async functions will then be stored in our store by the actions defined inside those domain stores only.

Models for your Mobx Store-

Think of defining the models as you define a schema in a Mongo database, so that once you define the model you can push new data into the Mobx store using that model.

Using this approach has many benefits:

  • You will have a single place where you define your Store schema.
  • You can change the schema according to your own needs.
  • You can reuse the model you defined for different store variables.
    It’s like if you have two kind of users in the app all having the same key-value pairs, you can define them in the same model if you like.

The model is a class wherein each of the class variables can be made as observables if you want Mobx to watch them, eg. you create a model (which is a class) called user , this will have variables such as name, DOB, interests etc.

So (say) inside your Mobx store is an array of users called userList Whenever you create a new user you basically create a new object of the class user . And then you push that new user inside your userList. So the userList array which just observed the child objects now also observes the name, DOB etc.

Problems I faced with Mobx and how to overcome them-

  1. Mobx didn’t re-render the ListView when I changed values in the ListView’s data source.

This is a simple Mobx store. list is an array of objects.

  • First of all my data source was an array of objects (collection) which were further nested objects. So when I tried to change a value(live) in the nested object Mobx didn’t re-render. This is because Mobx didn’t observe my array in depth. Had I inserted a new object in the array the list would have re-rendered perfectly.
  • So what we do is we make a model for each nested object / array and insert that model into our datasource. As you can see in the model code snippet, each variable in the model itself is an @observable. This tells Mobx to observe changes in that particular variable.
  • So now back to our Mobx store, we add new objects to list as follows:
  • Models is a very powerful tool as we can tell Mobx what values in an object do we need to observe. So we can optimize our re-rendering. Moreover you might think that having more observables might slow down your app, but it’s actually quite the opposite. In Mobx having more observables is good , more is the observables more the Mobx knows when and how much data has changed.

2. When reading Mobx data (say an array) it shows `undefined`.

I had hard time with this issue. Basically what I mean is when you store any data in the Mobx store, it wraps that data for it’s own purpose. So that data is not plain / JSON data, which means React will not be able to read it.

So every time you read the data from the Mobx store you need to convert it from an observable / wrapped data to plain data.

You can do that using:

const list = toJS(mobxStore.list);

now you can use this array in your React component like this:

Tools to help for simplifying your development:

  • Use mobx-logger to check what and how Mobx changes your store.
  • Use mobx-react-devtools to track the rendering behaviour and data dependency .Check this comment to see how that works.
  • Use mobx-persist to store data locally in your app for offline usage.

TIP: Make custom file links in your repo for easy imports.

To make it easy for you to import files when the folder structure is nested too much.

Wouldn’t it be cool if instead of:

import SignUpScreen from '../../storybook/stories/screens/signup';

You could just do:

import SignUpScreen from 'screens/signup';

To do this you need to install babel-plugin-module-resolver package as a dev dependency.

Then in your project’s .babelrc file you can write your custom alias:

Here’s the link to the repo so that you can view it on your own how we do that. I guess the code is pretty self explanatory!

About The Author

I am a JS developer here at GeekyAnts. I work on FullStack Mobile Applications.

PS. Thanks Sanket Sahu for all your help.

--

--

Full Stack Developer | Javascript | Music | Sketching | Tea | Coffee | Cats | Dogs. :D