Platform-specific module code
  • 10 Apr 2024
  • 3 Minutes to read
  • Dark
    Light
  • PDF

Platform-specific module code

  • Dark
    Light
  • PDF

Article summary

Our scaffold makes use of React Native, React, React Native for Web, and Django.

The following information is for React.  For information on Django, refer to Creating Django Modules.

Note

In this guide, “React Native” refers to Universal React Native Apps, built with:

  • React Native and Native Code on mobile platforms.
  • React Native and React Native for Web on the web.

Multi-platform support

When you build screens for mobile devices, you use React Native Core Components with React APIs.

When you build screens for web, you can use any of the following:

This means that you can reuse code across all platforms and, when it makes sense, you can separate platform-specific components. You might want to use different libraries for web and mobile or you might want different business logic on a specific platform. By default, start with a shared implementation for all platforms as this aims for the most code reuse possible, and only "specialize" your code to tailor a platform when necessary.

React-only components

React DOM refers to the React library that abstracts away the  DOM Web API. As an example, the following App component makes use of div, which is defined in the React DOM library.

function App() {
  return <div>Hello World</div>;
}

React-native Components

When sharing the same screen code for all platforms, we perform additional build steps for web. During your app's web build process, we rewrite all  react-native imports to point to  react-native-web instead. This provides a compatibility layer between React DOM and React Native. We also prioritize web-specific source code. We discuss this mechanism in more detail in the next section.

Platform-specific code

You have two options for controlling which pieces of source code get added to your web bundle: File extensions and Platform API. Both are explained below.

File extensions

The first and simplest tool that you have available is file extensions. Naming a file index.web.js (instead of index.js) sets this file to be picked for the web build. This is due to a system that prioritizes web extensions. The priority order is (from highest to lowest):

.web.js
.web.ts
.web.jsx
.web.tsx
.js
.ts
.jsx
.tsx

As an example, let's take a look at our "Date Picker" module:

// modules/date-picker/date-picker.web.js
import React, { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";

export const DatePickerComponent = () => {
  const [startDate, setStartDate] = useState(new Date());

  return <DatePicker selected={startDate} onChange={setStartDate} />;
};

This file is used when doing a web build of the app. You can see in the imports section that it depends on the react-datepicker library.

// modules/date-picker/date-picker.native.js
import React, { useState } from "react"
import DatePicker from "react-native-date-picker"

export const DatePickerComponent = () => {
  const [startDate, setStartDate] = useState(new Date())

  return <DatePicker date={startDate} onDateChange={setStartDate} />
}

This file is used in the mobile build of the app, and depends on the  react-native-date-picker library.

These files show how platform-specific components are specified using this file extension mechanism. They also show platform-specific dependencies or libraries.

Platform API

The second tool that you can use is React Native Platform API, which is much more granular in scope. With this API you can query the current platform at runtime. This allows for platform-specific business logic and more.

The following is the same Date Picker module you’ve seen before.

// modules/date-picker/index.js

import React from "react"
import {
  SafeAreaView,
  ScrollView,
  Text,
  Platform,
  StyleSheet
} from "react-native"
import { DatePickerComponent } from "./datepicker"

const DatePicker = () => {
  return (
    <SafeAreaView style={styles.container}>
      <ScrollView contentContainerStyle={styles.scrollView}>
        <Text style={styles.text}>Date picker for {Platform.OS}</Text>
        <DatePickerComponent />
      </ScrollView>
    </SafeAreaView>
  )
}

const styles = StyleSheet.create({
  container: {
    backgroundColor: "#F8F8FC",
    height: "100%"
  },
  scrollView: {
    flex: 1,
    alignItems: "center",
    justifyContent: "flex-start",
    padding: 20
  },
  text: {
    textAlign: "center",
    fontSize: 28,
    color: "#828AB0",
    fontWeight: 700,
    padding: 20
  }
})

export default {
  title: "Date Picker",
  navigator: DatePicker
}

Notice the <Text style={styles.text}>Date picker for {Platform.OS}</Text> line within const DatePicker. The Platform.OS property returns a string of the current OS at runtime.

With this information, you can perform platform-specific logic.  For example, you can show the OS in UI text as or you can use it in any JavaScript code to separate business logic for each OS (Platform). The following image shows the Date Picker with both of those examples.


Was this article helpful?