EXPLAINING THE CONCEPT
Let us first go through the concept. React Native can load the files on the basis of the current platform. For Example, we have two index files in our project:
React Native will automatically pick up the index.ios.html when the app is running on an IOS device and index.android.html when the app is running on an Android device. Apart from IOS and Android extensions, it has .native extension as well. This .native extension can be used when a module needs to be shared between React and React Native. For example, we have 2 separate views of a button in the web and app. We will make two different files for it with the following extensions:
- button.js (This is the view of the button in React)
- button.native.js (This is the view of the button in React Native)
Now I have a shared container component which imports the view like ->
import Button from “./button”
Now the webpack or any other web bundler will pick the button.js automatically while making a bundle whereas button.native.js will be picked by the React Native while making a bundle.
That’s it!!!!!! It’s that Simple and Amazing!!!!!. Now let us create some components/modules using this approach to reuse code between React and React Native.
I have done a POC around it and made a page, both in web and app, which is made up of dumb and smart components (with redux). The source code can be found here. In the App, I have made a simple page where you can take out all of your frustration on Thanos by hitting him hard. I hope I have your complete attention now. 🙂
This is how the folder structure looks like:
The Page mainly consists of a header, Main content, and Footer. All those components which need to be shared among app and web, are kept under the platform folder. Currently, two components named ThanosCaption and ThanosHitButton are in the folder. The former one is a dumb component while the latter one is a redux component. The Redux is also shared between both the platforms. In order to run React Native on your mobile, you would need to download the Expo app. You can read more about Expo app here.
This is how the Page looks like in Web and App:
Component with no logic
Inside the platform folder, we have one folder named Thanos Caption
Inside that folder we have:->
- thanosCaptionConatinerComponent.js:- This is the container component which internally imports the view on the basis of the platform we are running the code on.
- thanosCaptionView.js:- This component contains the view of the Thanos caption for the web.
- thanosCaptionView.native.js:- This contains the view of the Thanos caption for the app
Now let us look inside the container component ‘thanosCaptionConatinerComponent.js’
This component simply imports ThanosCaptionView. Remember that we are importing the view from a file without extension specified. The correct extension will be picked up while making the bundle by webpack and react native.
If the bundle is being made up webpack, means the bundle is being prepared for web, then ThanosCaptionView from thanosCaptionView.js will be picked automatically. If the bundle is being made by React Native/Expo, means the bundle is being prepared for mobile app, then ThanosCaptionView from thanosCaptionView.native.js will be picked automatically.
Now let us quickly look inside these two views.
This is the view which will be rendered for Web. This component simply renders the image of Mr.Thanos.
This is the view which will be rendered for Mobile App. This component simply renders the image of Mr.Thanos.
Component with logic
Now let us jump on the other component inside the platform folder which is thanosHitButton.
Again we have three different files under this folder:->
- hitButtonConatinerComponent.js:-> This is the container component which has the logic and internally imports the view on the basis of the platform we are running the code on.
- hitButtonView.js:-> This component contains the view for the web.
- hitButtonView.native.js:-> This component contains the view for app.
Before visiting the container component let us look where are my actions and reducers for this component and how the store is getting initialized in both the platforms. All the common actions and reducers are at the root folder which is shared among web and mobile app.
So the action which hitButtonContainerComponent.js is dispatching sits under actions folder which is at the root of the project.
We have the same code for initializing the store for both the mobile app and web which is at the root of the project in initialzeStore.js. Following is the snippet of the code inside that file.
Now index.web.js (entry point for web) and App.js(entry point for the app) calls this function to get the store in their respective platforms. Let us look inside both the files quickly.
Finally!!!!!!!! Now let us look inside the hitButtonContainerComponent.js
As we can see that the Logic to increase the Hit Count and to dispatch the action to store is written in this container component. Hence the logic and the redux become common in both the platforms.
This component simply imports HitButton. Remember that we are importing the view from a file without extension. The correct extension will be picked up while making the bundle by webpack and react native.
Let us have a look into the views.
This is the view which will be rendered for Web. This component simply renders the button which calls the handler, passed on by the container, when the user clicks on the button.
This is the view which will be rendered for App. This component simply renders the button which calls the handler, passed on by the container, when the user clicks on the button.
We analyzed how to share code between React and React Native with different types of components. This technique is really simple and really effective to use. The Demo application is very simple and does not follow best practices and should not be used as an example of a well designed React application.
If you want to play around the Application then please go ahead and fork the repo from here. If you have any questions or feedback then please do share the same in comments. I will be more than happy to help.