Reactive Core architecture for React Native and React applications
When it comes to develop an application that needs a mobile app and a web app, there is always a struggle in the matter of what is the right approach to take. You can build a web app and a native mobile application for each operative system. The performance and user experience will be neat, however you don’t want to write the mobile application 2–3 times in different programming languages. Also you want to build the applications faster and minimize the resources but keeping performance and user experience.
Some modern frameworks promise that you will be able to “Write once, run anywhere”. Applications developed with this frameworks are labeled as “mobile web app”, “HTML5 app”, “hybrid app”, where your app is basically a responsive web page loaded in a webview. This approach has more disadvantages than advantages: the performance of the application decreases, transitions, animations, clicks, everything becomes slower, making the users don’t want to use the application anymore. The application loses the native look and feel of mobile platforms. The developer experience, debugging, integrations with other systems, becomes more complicated than it should be.
This article proposes an architecture "Reactive Core Architecture" that allows to have just one code base for the logic and keep the native UI and the web UI separated, maximizing code reuse and maintaining consistency across platforms.
Some of the advantages are consistency, code maintainability, testing gets easier and performance is high. The latter is really important, because the mobile app will still be native, so the performance won’t be affected.
For this purpose the Redux framework, in conjunction with Git submodules, are used to structure a common core codebase. React Native is used for the mobile application and React is used for the web application.
Then we have the powerful git submodules tool, which gives you the ability to add a git project inside another git project. The child repository doesn’t know anything about its parent repository, but the parent can access the child and keep track of the version of the child.
The Reactive Core Architecture
The proposed architecture is composed by three modules:
- The core: Includes the business logic and the state of the application. This component is implemented using the Redux framework. Code reuse is done via this module.
- The mobile app: Implemented as a standard React Native application, using containers and components.
- The web application: Implemented as a standard React application, using containers and components.
Each module will live in its own repository, with the core as a git submodule in both applications.
Let’s take a look to the architecture diagram:
- The core module.
Consists on a basic Redux structure, meaning you have a folder for the actions and a folder for the reducers.
This is the most important module to make the Reactive Core Architecture possible. It’s the only one able to handle and mutate the application state. It’s the brain that tells the mobile and web applications how to behave and react. It's also the clear candidate to consume a REST API and process data. Since each reducer handles an specific part of the application state, it makes easier for the core module to scale for larger and more complex applications.
- The mobile app and the web app.
Both the React Native app and the React app, use components and containers concepts. The components render the UI blocks. The containers connect the Redux actions with the UI components.
In the folder where you have the containers and the components, run the following command to add the core module as a submodule:
git submodule add <core-module-git-repo-url> --name core-module
By default, the submodule root folder name will be the name of the repository. Rename it to match the name of the submodule by executing:
git mv <core-module-git-repo-name> core-module
The folder tree now looks like:
If you move into core-module folder and execute:
git remote show origin
You may note that it’s pointing to the core module repository. If you make changes there, commit them and push them, they will be reflected in that repository.
Please note that the submodule is pinned to a specific revision of the child repository in the parent repository. So, if the local submodule changes you will need to git add the submodule to pin it to the newer version.
In the same way, if you pulled the latest version of your parent project and the pinned reference changed in remote, you can update the child repository by executing the following command:
git submodule update --recursive --remote
That’s all you need! Easy and clean!
Conclusion and future work
The architecture presented in this article allows to structure a project for both a multi-platform mobile application and a web application, keeping the business logic of the application in a single, self-contained, reusable and maintainable submodule.
While this architecture focus on business logic reuse, there still are other elements of an application that could be reused and shared among applications. In particular, for some projects you may find that the containers could be candidates to live in the core module but that depends of the applications, definitely something nice to try out.
Another common issue to solve is making the style and branding reusable. In particular, React and React Native uses different mechanisms to declare it (CSS vs StyleSheet) so the challenge is how to create a consistent and shareable visual identity for your applications.
Want to see it in code? Check out the example project:
It's a simple application that lists all doctors of the Doctor Who series. This list is sourced from a JSON file that lives in the reactive core. It uses actions to get the doctors, go to a doctor detail and order them by name and by doctor number.