react & react native at once : 1 app = 1 program ?

One question everyone is likely to ask one day, while using the react framework, is :

« can I use the same app on a browser AND on a mobile device without rewriting the app ? » In other words, is the principle « write once, run everywhere » respected ?

The short answer is no, and the longer one is « yes but ».
There is a quite simple to trick to make a react app work on different devices.

On a react-web app, you will write this kind of render :
<div>

<div>This is some text</div>
<img src= »logo.png » alt= »this is a picture » />

</div>
Whereas on a react-native app, the layout would look like this one :

<View><Text>This is some text</Text>
<Image source= »logo.png » alt= »this is a picture »/></View>

Quite similar, isn’t it ? But problem is that you cannot declare a common declaration for both environments.

…Or you would need to branch with an if instruction. That will work, but it will make the code less concise and you will have some ‘copy/paste’ sessions between your components.

I found a better option, not the best one (I am more of a beginner in react) : Just provide the same language to both environment. Declare a provider in each environment, and make it provide exactly the same markup with some common attributes.

This is how your code looked like before :

import {View, TextInput} from 'react-native'
export default class Console extends Component {
render(){return (
 <View className="console" style={{height:'100%', width:'100%', flex: 1}}>
 <TextInput id="commandLine" value={this.state.command}/>
 </View>
) /* and it only works on a mobile */
}}

And this is how you can change it to make it work on several envs :

export default class Console extends Component {
render(){
const [View, TextInput] = ['View', 'TextInput'].map(componentName => this.context.componentsProvider(componentName))
return (
 <View className="console" style={{height:'100%', width:'100%', flex: 1}}>
 <TextInput id="commandLine" value={this.state.command}/>
 </View>
) /* and it only works on a mobile */
}}

And last but not least, declare a provider which will gives you these elements :

import { Component } from 'react'
import PropTypes from 'prop-types'

export default class ComponentsProvider extends Component {
    getChildContext() {
        return {
            componentsProvider: this.props.impl,
        }
    }

    render() {
        return this.props.children;
    }
}

ComponentsProvider.propTypes = {
    children: PropTypes.element,
    impl: PropTypes.func.isRequired
}
ComponentsProvider.childContextTypes = {
    componentsProvider: PropTypes.func.isRequired,
}


Your app will need to be surrounded by your provider, in each version :

<ComponentsProvider impl={(name) => nativeMapping(name) || ReactNative[name] || MaterialUi[name] || ReactNative.View}>
    <MaterialUi.ThemeProvider uiTheme={uiTheme}>
        <App muiTheme={uiTheme} />
    </MaterialUi.ThemeProvider>
</ComponentsProvider>


Now you are ready to deploy the same app on different devices with very little effort.

Please have a look at my NON-HELLOWORLD example : https://github.com/libetl/amadeus-console
I deployed the same app on google chrome and android. The app is what you see on the screen when you board in a plane or when you complain about your flight booking. The UI is a kind of a console which can help you manage all your bookings.