- 10 Apr 2024
- 3 Minutes to read
- Print
- DarkLight
- PDF
Platform-specific module code
- Updated on 10 Apr 2024
- 3 Minutes to read
- Print
- DarkLight
- PDF
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.
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:
React-only components with React DOM
React-native components that get converted into React DOM via React Native for Web;
A combination of both
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.