This is a WIP being tested and developed only on Android and Browsers. iOS will be part of the scope soon...
The concept executed is 99.9% inspired and based on Sharing components between React and React Native and A mobile, desktop and website App with the same code
React Forum Discussion on this topic here
StackOverFlow Discussion on this topic here
Make sure you have Node JS 4.0.0 or higher installed.
npm install -g webpack-dev-server
npm install -g react-native react-native-cli
npm install
To run the web example, first run the following commands :
npm run start-web
Now navigate to http://localhost:8080/
To run Android, first start an android emulator (or connect your phone with USB debugging enabled), then run the following commands :
react-native run-android
npm start
To run on a device or emulator without the Dev server, run the following command:
react-native bundle --entry-file src/index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --platform android --dev false
react-native run-android
To run iOS, open up ios/SampleApp.xcodeproj
in XCode, and click Run (the big play button).
- android/ -----> native shell
- ios/ -----> native shell
- web/ -----> web shell
- src/ -----> insert your code here!
- actions/ -----> Shared across
- constants/ -----> Shared across
- reducers/ -----> Shared across
- components/
- index.android.js
- index.ios.js
- index.web.js
Following React-Native naming convention, we extend it by adding '.web' as indicator for web platform related files.
React-Native will be looking for index.js or index.ios.js or index.android.js
React + WebPack will take index.web.js as entry point for our Web js bundle.
In order to create a single component, some boilerplate is required.
- components
- MyComponent
- MyComponent.native.js -----> Until react and react-dom is fully separated
- MyComponent.web.js -----> Until react and react-dom is fully separated
- MyComponentLogic.js -----> Shared across
- MyComponentRender.android.js -----> Android Specific Render
- MyComponentRender.ios.js -----> iOS Specific Render
- MyComponentRender.native.js -----> Android/iOS Sahred Render
- MyComponentRender.web.js -----> Web Specific Render
- __tests__
- MyComponentRender.native.test.js -----> Test Native Render Output
- MyComponentRender.web.test.js -----> Test Web Render Output
- MyComponentLogic.test.js -----> Test Shared Logic
To avoid this we have created a yeoman generator for this specific purpose.
The generator was already installed when you executed 'npm install'.
In order to use it,
cd /src/components
yo react-dom-native:component MyComponent
You pass in the component name and it will generate all necessary files and its content.
- Generic Component
- Logic
- Render
Ideally every component has a main Class
which inherits a base Class
containing all the logic. Then, the main component import a different Render function which has been selected during the build. The file extension .ios.js
, .android.js
or .js
is used by the build tool to import only the right file. The .js
being picked for the Web portion.
React 0.14 announced the start point of the separation of react and react-dom. This would allow us to create that base react component that has no dependency on a DOM or a native View.
Unfortunately as in 0.14.3 the dependency still exists.
In order to mitigate this problem, we need to create a base component for native and one for web:
- MyComponent.native.js
- MyComponent.web.js.
Since we are forced to create these, we have selected .native
and .web
to avoid confusions on the targeted platform.
When the separation by React team is completed, we could have just one MyComponent.js thta creates a generic react component.
Following Redux concept you will code most of the application logic in Actions and Reducers. These are already shared across all components.
MyComponentLogic is where we could add shared logic specific to a visual aspect of a component. For example, execute an action when the component is mounted, cleaning up a visual hint or input. Both native and web components will use it without any dependency on the DOM or native Views
- MyComponentRender.android.js -----> Android Specific Render
- MyComponentRender.ios.js -----> iOS Specific Render
- MyComponentRender.native.js -----> Android/iOS Sahred Render
- MyComponentRender.web.js -----> Web Specific Render
'.android' and '.ios' will be the ones react-native will look for. In the absence it will look for '.js'.
We have purposely avoided leaving '.js' files since it could be confusing if these are web or native related.
Instead, we enforce the use of '.web' as a convention.
What if you still want to have a common Render for ios and android. In that case, we delegate to a common file with '.native' extension.
Redux is traditionally followed by separation of Container (logic) and Presentational components.
On the web you will find Redux examples including a containers folder.
This project follows the same concept but keeps all parts in the same component folder.
npm test
npm run tdd