Before we Start React-Native-Web

  • Basic understanding of React (understanding React native as well is preferred but not necessary)
  • Some understanding of ES6
  • Have npm installed on your machine
  • yarn install. If you don’t, feel free to substitute any instance of yarn add ... with npm install -S ....

Downloading Expo

Download the Expo XDE through the above link. Expo will save us the headache of running iOS/Android simulators on our machine. With Expo, you can create a React Native app and test it on your own phone. There is an CLI as well that you could use, but we’ll be using the XDE for this project. Once you’ve done that, open it and register an account if you haven’t already.

Expo on your Phone

Through the link, find and download Expo client for the mobile device (iOS version, or Android) on which you’ll be testing. Once it’s downloaded, log in using the same account you’re using with the XDE.

Create your app

Open theExpo XDE and click ‘create new project…’ to create an app. Use the blank template.

Run your app

  • Open the expo client on your device
  • Your project should appear under ‘Recently in Development’
  • Click it and wait while the Javacript bundle is built on your phone
  • You should see the following screen on your device
  • Change some text in App.js and save it, and your app should automatically reload with the updated text

2) Then Web

Dependencies

Let’s start by getting the necessary packages to run this on the web.

Open your terminal, navigate to the project folder and then run the following command:

yarn add react-scripts react-dom react-native-web react-art react-router-native react-router-dom

Here’s what we’re adding:

  • react-scripts: contains the scripts used in create-react-app.
  • react-dom: allows react-code to be rendered into an HTML page
  • react-native-web: the main source of magic in this app. This library will convert our react-native components into web elements. Thankfully, react-scripts is already configured to use it, so you won’t need to touch any Webpack yourself to get it up and running
  • react-art: a peer dependency for react-native-web
  • react-router-native: routing library for React Native
  • react-router-dom: routing library for React on the web

File Restructure

We need to have two separate entry points which point to the same root application. One App.js will be used by Expo, and the other src/index.jswill be used by react-scripts to be rendered on the web.

  • Create a folder called src and copy the existing App.js into it to create src/App.js
  • Refactor your root folder’s App.js so that it simply imports and renders the src/App.js that you just created
// /App.js
import React from 'react';
import HybridApp from './src/App';
const App = (props) => {
  return (
    <HybridApp />
  );
}
export default App;
  • Create a folder called public and create public/index.html
  • In your index.html simply make a html skeleton, with <div id="root"></div> in the body so that your app has somewhere to render
<!-- public/index.html -->
<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8" />
      <title>Pokedex</title>
   </head>
   <body>
      <div id="root"></div>
   </body>
</html>
  • In your src folder, create index.js and write the following code to have it render your app into the DOM
// src/index.js
import React from 'react';
import ReactDom from 'react-dom';
import App from './App';
ReactDom.render(<App />, document.getElementById("root"));

Scripts

react-scripts is automatically configured to recognize React Native code and translate it using the react-native-web library that we imported. That’s why we can make this work without pulling our hair out over Webpack configurations. All we need to do now is set some scripts in our package.jsonso that we can easily run it.

Add the following property to your package.json

// package.json
"scripts": {
    "start-web": "react-scripts start",
    "build-web": "react-scripts build"
  },

Run it on the Web

In your terminal, run yarn start-web and in moments your web app should appear in the browser. Congratulations, you have created your first hybrid app!

Now let’s make this app do something.

Adding Content and Functionality

Let’s start off simple by adding a list of Pokemon.

To keep things simple, we’ll just store our list of Pokemon insrc/spokemonStore.js.

// src/pokemonStore.js
export default [
  {
    number: '1',
    name: 'Bulbasaur',
    photoUrl: 'https://assets.pokemon.com/assets/cms2/img/pokedex/full/001.png',
    type: 'grass'
  },
  {
    number: '4',
    name: 'Charmander',
    photoUrl: 'https://assets.pokemon.com/assets/cms2/img/pokedex/full/004.png',
    type: 'fire'
  },
  {
    number: '7',
    name: 'Squirtle',
    photoUrl: 'https://assets.pokemon.com/assets/cms2/img/pokedex/full/007.png',
    type: 'water'
  }
];

Instead of using map, we’ll follow React Native convention and use FlatList, as it will work just fine with react-native-web.

// src/App.js
import React, { Component } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import pokemon from './pokemonStore'
class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <FlatList
          keyExtractor={pokemon => pokemon.number}
          data={pokemon}
          renderItem={({ item }) => <Text>{item.name}</Text>}
        />
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: 50,
    padding: 50
  },
});
export default App;

Platform-Specific Styles

Note: It won’t be an issue for a barebones project like ours, but in your own projects, you may have to adjust the styles web layout so that it looks similar to your native app. To do so, you can create src/index.css with your web-specific adjustments and and import it into index.js.

/* src/index.css */#root {
  /* layout adjustments for web app */}

However, that will effect the layout of that app as a whole. Inevitably we need to figure out away to change specific parts of the app based on the platform, and this is where things get interesting.

Read More:   Mobile App UX Design: A Quick Introduction (2023)

Platform-Specific Code

We need to add some basic routing so that we can go from viewing a list of Pokemon to the details of a single Pokemon. react-router-dom is great for the web, and another library, react-router-native, is great for React Native. To keep our code clean, we will create a generic Routing.js file that will abstract that distinction and be available throughout our code.

We will create routing.web.js with components from one library and routing.native.js with similarly named equivalents from the other. Import statements to our routing files will omit the file extension, and because of that, the compiler will automatically import whichever one is relevant to the platform for which the app is being compiled and ignore the other.

This will allow us to avoid writing code that checks for the platform and uses the appropriate library every single time we use routing.

First create the web version of your routing file src/routing.web.js

export {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from 'react-router-dom';

Then, the native version, src/routing.native.js .

export {
  NativeRouter as Router,
  Switch,
  Route,
  Link
} from 'react-router-native';

Now, create two files, Home.js and Pokemon.js . These will be the components rendered by your routes.

In Home.js, simply render a list of Pokemon like you did in App.js.

// src/Home.js
import React from 'react';
import { View, Text, FlatList } from 'react-native';
import pokemon from './pokemonStore';
const Home = props => {
  return (
    <View>
      <FlatList
        keyExtractor={pokemon => pokemon.number}
        data={pokemon}
        renderItem={({ item }) => <Text>{item.name}</Text>}
      />
    </View>
  );
};
export default Home;

In Pokemon.js render information about a single Pokemon. You can hard-code in one now as a placeholder. We’ll refactor and tie everything together after we’re sure that the routing works.

// src/Pokemon.js
import React from 'react';
import { View, Text, Image } from 'react-native';
import pokemon from './pokemonStore';
const Pokemon = props => {
  const examplePokemon = pokemon[0];
  return (
    <View>
      <View>
        <View>
          <Text>{`#${examplePokemon.number}`}</Text>
        </View>
        <View>
          <Text>{`Name: ${examplePokemon.name}`}</Text>
        </View>
        <View>
          <Text>{`Type: ${examplePokemon.type}`}</Text>
        </View>
        <View>
          <Image
            style={{ width: 50, height: 50 }}
            source={{ uri: examplePokemon.photoUrl }}
          />
        </View>
      </View>
    </View>
  );
};
export default Pokemon;

Now change your App.js so that it now simply renders your routes. One for each component. Make sure you pass in all of the route’s props into the component by adding {…props}. You’ll need that in order to access the ‘history’ prop which can be used to change routes.

// src/App.js
import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { Router, Switch, Route } from './routing';
import Home from './Home';
import Pokemon from './Pokemon';
class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Router>
          <Switch>
            <Route exact path="/" render={props => <Home {...props} />} />
            <Route path="/pokemon" render={props => <Pokemon {...props} />} />
          </Switch>
        </Router>
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: 50,
    padding: 50
  }
});
export default App;

Refresh your app and make sure that each route works by changing the address bar manually. Therefore, deliberately adding a ‘render’ prop instead of ‘component’ into each route because we’ll be passing in some props to each component as we render them.

Your root route will look the same as before. Type ‘localhost:3000/pokemon’ in your address bar and this what you should get:

Tying it all Together.

Now it’s time to add some logic to make this app work. We need to do the following:

  • In App.js, create a function called selectPokemon which takes a Pokemon as an argument and sets it to the App state as ‘selectedPokemon’. To prevent errors, set a default state with a ‘selectedPokemon’ set to null
  • Pass selectPokemon into Home.js through its props
  • In Home.js Wrap each Pokemon in the list in a <TouchableOpacity />component so that, once clicked, it can: a) Call selectPokemon and pass in the pokemon as an argument and b) call this.props.history.push(‘/pokemon’) in order to switch to the Pokemon route
  • In App.js, pass in a prop called selectedPokemon into the <Pokemon /> being rendered in the second route. It’s value should be this.state.selectedPokemon, which will be undefined until you select a Pokemon.
  • In the Pokemon component, remove the reference to the pokemonStore and instead refer to props.selectedPokemon. It would be a good idea to also add some default content that is conditionally shown if no Pokemon is selected.
  • Create View and some Text with the message ‘return to home’. To make it work, wrap it with a <Link/> Tag from your routing file and in that Link component, add the property ‘to=”/”’ to have it redirect to your home route.
Read More:   3 Key Benefits of Mobile Apps for Small Businesses

Here are what your three changed files should now look like:

// src/App.js
import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { Router, Switch, Route } from './routing';
import Home from './Home';
import Pokemon from './Pokemon';
class App extends Component {
  state = {
    selectedPokemon: null
  };
  selectPokemon = selectedPokemon => {
    this.setState({
      selectedPokemon
    });
  };
  render() {
    return (
      <View style={styles.container}>
        <Router>
          <Switch>
            <Route
              exact
              path="/"
              render={props => (
                <Home {...props} selectPokemon={this.selectPokemon} />
              )}
            />
            <Route
              path="/pokemon"
              render={props => (
                <Pokemon
                  {...props}
                  selectedPokemon={this.state.selectedPokemon}
                />
              )}
            />
          </Switch>
        </Router>
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: 50,
    padding: 50
  }
});
export default App;
// src/Home.js
import React from 'react';
import { 
  View,
  Text,
  FlatList,
  TouchableOpacity
} from 'react-native';
import pokemon from './pokemonStore';
const Home = props => {
  const handlePress = pokemon => {
    props.selectPokemon(pokemon);
    props.history.push('/pokemon');
  };
  return (
    <View>
      <FlatList
        keyExtractor={pokemon => pokemon.number}
        data={pokemon}
        renderItem={({ item }) => (
          <TouchableOpacity onPress={() => handlePress(item)}>
            <Text>{item.name}</Text>
          </TouchableOpacity>
        )}
      />
    </View>
  );
};
export default Home;
// src/Pokemon.js
import React from 'react';
import { View, Text, Image } from 'react-native';
import { Link } from './routing';
const Pokemon = props => {
  const backButton = (
    <View>
      <Link to="/">
        <Text>Go Back</Text>
      </Link>
    </View>
  );
  if (!props.selectedPokemon) {
    return (
      <View>
        {backButton}
        <Text>No Pokemon selected</Text>
      </View>
    );
  }
  const {
    selectedPokemon: { name, number, type, photoUrl }
  } = props;
  return (
    <View>
      <View>
        {backButton}
        <View>
          <Text>{`#${number}`}</Text>
        </View>
        <View>
          <Text>{`Name: ${name}`}</Text>
        </View>
        <View>
          <Text>{`Type: ${type}`}</Text>
        </View>
        <View>
          <Image style={{ width: 50, height: 50 }} source={{ uri: photoUrl }} />
        </View>
      </View>
    </View>
  );
};
export default Pokemon;

You’re done! and should now be able to load your app, see a list of Pokemon, click on one to see more it’s details, and then press ‘Go back’ to see your list again.

Bonus tip: Platform-Specific code — The ‘Share’ Button

I showed you how to separate code for different platforms by using different files. However, there will likely be times where you have plaftorm-specific logic that can be solved in such a simple way. For example, we’re going to show a ‘share’ button in our Pokemon view, but we only need it on mobile. It would be overkill to make two versions of that entire component just to hide or show one feature. Instead, we’ll simply hide the functionality where it’s not needed. React Native gives us access to a Platform object, which contains a property called ‘OS’ with a value that changes with the operating system of whichever platform your app is running on. We can use that to hide or show our ‘share’ button accordingly.


 // Make sure you import { Platform } from 'react-native';
handlePress = () => {
  Share.share({ 
    message: 'Check out my favorite Pokemon!',
    url: props.selectePokemon.photoUrl
  })
};
...
{ Platform.OS !== 'web' &&
  <View>
    <Button title="Share" onPress={this.handlePress}/>
  </View>
}

As our example is relatively simple, but building a universal React app will inevitably get tricky as you add scale and functionality, since many React Native libraries have little to no compatibility with the web, and even those that do will often require some tinkering with Webpack in order to work. And you should also keep in mind that Expo, as much as it significantly simplifies setup, adds some limitation to the libraries that you can work with. If you’d like to know details about compatibility with specific libraries, this list would be a great place to start:

https://native.directory

Source: InApps.net

List of Keywords users find our article on Google:

react router
flatlist expo
react router dom
react-scripts
react-router-dom
react scripts
react native search flatlist
flatlist search react native
react native search bar flatlist
search in flatlist react native
react native flatlist search
react router redirect
react native flatlist
flatlist react native
search flatlist react native
react select
substitute pokemon
react-router
switch react router dom
react-native-render-html
pokemon let’s go route 1
react dom router
this props react native
import react dom
react route
universal yarn
react router 4
react router example
expo status bar height
npm router
pokemon all routes
flatlist
react router dom npm
react-router-dom redirect
react router dom link
history push in react
react-router-dom switch
pokemon hair tie
route render
what is react router
react router-dom
entire pokedex
npm install react router dom
hrm flex
expo cli version
react routing
react native blank screen
flatlist search
hybrid app developer jobs
react native textinput style example
magic edtech
react router dom redirect
router route react
body press pokemon
jsexport
react router history back
this.props.history
clickit devops & software development
that ll for sure grab the audience a yarn that s definitely gonna win
pokemon route
add ecommerce to platformos
react router npm
npm react-scripts
react router link refresh page
flex hrm mobile
pokemon x routes
bulbasaur png
react native touchableopacity
react native view onpress
react-router-dom npm
npm react router
squirtle png
responsive flatlist react native
pokemon go export pokemon list
charmander png
expo remove package
it’s a wrap yarn
npm react scripts
react-native-phone-input
react-native-phone-input npm
react native router
budget home store folder
expo client download
wawa library
flatlist react native web
how much is a basic charmander
hybrid app
react json view
react-native-maps
expo xde download
react router-dom npm
export ‘switch’ (imported as ‘switch’) was not found in ‘react-router-dom’
pokemon 001
react flatlist example
flatlist keyextractor
flex hrm login
pokemon 004
react native code push
react router link
history push
wrap pokemon
flat list in react native
react native routing
route 4 pokemon let’s go
router react native
yarn substitute
native router
pokemon wrap
react native image view
react-json-view
routing in react native
touchableopacity
appstate writing center
flex hrm
pokemon index number
react native text
routing react native
text input react native
upload image react hooks
expo react native
importhome
link react router dom
npm install expo cli
react app blank page
react package.json
route props
update react-scripts to 5
yarn add dev
expo start new project
how to pass props in react
list of pokemon by number
router in react native
difference between react router and react router dom
pokemon by height
react json viewer
react native call keep
react-roter-dom
directory build props
exact react router
react js router
react router dom react native
react router react native
route 10 pokemon x
viewstyle
whatsappweb js
download expo go
prop types npm
add react router
app waitwhile
how to install switch in react
react native route
react native share image
react native text link
react router dom in react js
route render react
routing with react native
history.push is not a function
install expo cli
react app showing blank page
react router history push
yarn add –save
pokemon template
react-router-dom 5
router link react
router react js
angularjs reload page
code push react native
react native list
react router react
start new expo project
react native reload page
react router default route
react routerdom
react-router redirect
how to add react router dom
react native image scale
react route element props
router example react
routing in react
webpack require import
angularjs reloadonsearch
pokemon substitute
react native reload screen
react router with router
redirect react router dom
flex cli
hair developer substitute
how to install router dom in react
reactnative list
redirect in react
route component react
routes in react
switch in react router
(possible exports: default) react
class app extends react.component
react native placeholder
react native share link
react refresh webpack
react router use history
react routing without react router
render react router
webreact
image view react native
react-router exact
routerswitch.com
routing for react
routing with react
yarn blanks
create react app page title
default path react router
how much does bulbasaur cost
link to another component react
react router history
reactrouter
router react
using react router dom
browserrouter is not working
document.getelementbyid is not a function react
magic ed tech
react location vs react router
react native navigate to another screen
react router hooks
react router in react
react-router-dom route
reactjs router redirect
yarn add peer dependency
expo router
react admin custom routes
react app router
react as prop
react router dom switch
react-router-dom navigate
skeleton root
how to add pokemon to pokemon home
react image from public folder
react js setstate
reactdom.render
routes route react
check react native cli version
import redirect react
import three js in react
react link router
react native load more
react redirect to url
react router for react native
set image in react native
test routes app
whatsapp key extractor
check the render method of `link`.
import react and react dom
in-app messaging case studies
pokemon script
pokemon type icons
react link component
react native map example
react-router vs react-router-dom
setstate not working
switch in react js
android textview style example
hybridrouter
react convert html to react component
react native search list
react redirect to page
react router dom route component
textview placeholder
use of exact in react router
react role based components
hybrid app development
react native development services
Rate this post
As a Senior Tech Enthusiast, I bring a decade of experience to the realm of tech writing, blending deep industry knowledge with a passion for storytelling. With expertise in software development to emerging tech trends like AI and IoT—my articles not only inform but also inspire. My journey in tech writing has been marked by a commitment to accuracy, clarity, and engaging storytelling, making me a trusted voice in the tech community.

Let’s create the next big thing together!

Coming together is a beginning. Keeping together is progress. Working together is success.

Let’s talk

Get a custom Proposal

Please fill in your information and your need to get a suitable solution.

    You need to enter your email to download

      [cf7sr-simple-recaptcha]

      Success. Downloading...