React Adaptive Loading Hooks & Utilities ·
Deliver experiences best suited to a user's device and network constraints (experimental)
This is a suite of React Hooks and utilities for adaptive loading based on a user's:
It can be used to add patterns for adaptive resource loading, data-fetching, code-splitting and capability toggling.
Objective
Make it easier to target low-end devices while progressively adding high-end-only features on top. Using these hooks and utilities can help you give users a great experience best suited to their device and network constraints.
Installation
npm i react-adaptive-hooks --save
or yarn add react-adaptive-hooks
Usage
You can import the hooks you wish to use as follows:
;;;;
and then use them in your components. Examples for each hook and utility can be found below:
Network
useNetworkStatus
React hook for adapting based on network status (effective connection type)
; ; const MyComponent = { const effectiveConnectionType = ; let media; return <div>media</div>;};
effectiveConnectionType
values can be slow-2g
, 2g
, 3g
, or 4g
.
This hook accepts an optional initialEffectiveConnectionType
string argument, which can be used to provide a effectiveConnectionType
state value when the user's browser does not support the relevant NetworkInformation API. Passing an initial value can also prove useful for server-side rendering, where the developer can pass an ECT Client Hint to detect the effective network connection type.
// Inside of a functional React componentconst initialEffectiveConnectionType = '4g';const effectiveConnectionType = ;
Save Data
useSaveData
utility for adapting based on the user's browser Data Saver preferences.
; ; const MyComponent = { const saveData = ; return <div> saveData ? <img src='...' /> : <video muted controls>...</video> </div> ;};
saveData
values can be true
or false
.
This hook accepts an optional initialSaveDataStatus
boolean argument, which can be used to provide a saveData
state value when the user's browser does not support the relevant NetworkInformation API. Passing an initial value can also prove useful for server-side rendering, where the developer can pass a server Save-Data Client Hint that has been converted to a boolean to detect the user's data saving preference.
// Inside of a functional React componentconst initialSaveDataStatus = true;const saveData = ;
CPU Cores / Hardware Concurrency
useHardwareConcurrency
utility for adapting to the number of logical CPU processor cores on the user's device.
; ; const MyComponent = { const numberOfLogicalProcessors = ; return <div> numberOfLogicalProcessors <= 4 ? <img src='...' /> : <video muted controls>...</video> </div> ;};
numberOfLogicalProcessors
values can be the number of logical processors available to run threads on the user's device.
Memory
useMemoryStatus
utility for adapting based on the user's device memory (RAM)
; ; const MyComponent = { const deviceMemory = ; return <div> deviceMemory < 4 ? <img src='...' /> : <video muted controls>...</video> </div> ;};
deviceMemory
values can be the approximate amount of device memory in gigabytes.
This hook accepts an optional initialMemoryStatus
object argument, which can be used to provide a deviceMemory
state value when the user's browser does not support the relevant DeviceMemory API. Passing an initial value can also prove useful for server-side rendering, where the developer can pass a server Device-Memory Client Hint to detect the memory capacity of the user's device.
// Inside of a functional React componentconst initialMemoryStatus = deviceMemory: 4 ;const deviceMemory = ;
Adaptive Code-loading & Code-splitting
Code-loading
Deliver a light, interactive core experience to users and progressively add high-end-only features on top, if a user's hardware can handle it. Below is an example using the Network Status hook:
; ; const Full = ;const Light = ; const MyComponent = { const effectiveConnectionType = ; return <div> <Suspense fallback=<div>Loading...</div>> effectiveConnectionType === '4g' ? <Full /> : <Light /> </Suspense> </div> ;}; ;
Light.js:
; const Light = <img src=imageUrl ...rest />; ;
Full.js:
;; const Full = <Magnifier src=imageUrl ...rest />; ;
Code-splitting
We can extend React.lazy()
by incorporating a check for a device or network signal. Below is an example of network-aware code-splitting. This allows us to conditionally load a light core experience or full-fat experience depending on the user's effective connection speed (via navigator.connection.effectiveType
).
; const Component = React; const App = { return <div className='App'> <Suspense fallback=<div>Loading...</div>> <Component /> </Suspense> </div> ;}; ;
Browser Support
-
Network Information API - effectiveType is available in Chrome 61+, Opera 48+, Edge 76+, Chrome for Android 76+, Firefox for Android 68+
-
Save Data API is available in Chrome 65+, Opera 62+, Chrome for Android 76+, Opera for Android 46+
-
Hardware Concurrency API is available in Chrome 37+, Safari 10.1+, Firefox 48+, Opera 24+, Edge 15+, Chrome for Android 76+, Safari on iOS 10.3+, Firefox for Android 68+, Opera for Android 46+
-
Performance memory API is a non-standard and only available in Chrome 7+, Opera, Chrome for Android 18+, Opera for Android
-
Device Memory API is available in Chrome 63+, Opera 50+, Chrome for Android 76+, Opera for Android 46+
Demos
Network
-
Network-aware loading with create-react-app (Live)
-
Network-aware code-splitting with create-react-app (Live)
-
Network-aware data-fetching with create-react-app (Live)
Save Data
- React Twitter - save-data loading based on Client Hint (Live)
- React Twitter - save-data loading based on Hook (Live)
CPU Cores / Hardware Concurrency
- Hardware concurrency considerate code-splitting with create-react-app (Live)
- Hardware concurrency considerate loading with create-react-app (Live)
Memory
-
Memory considerate loading with create-react-app (Live)
-
Memory considerate loading (SketchFab version) with create-react-app (Live)
-
Memory-considerate animation-toggling with create-next-app (Live)
Hybrid
References
- Adaptive serving based on network quality
- Adaptive Serving using JavaScript and the Network Information API
- Serving Adaptive Components Using the Network Information API
License
Licensed under the Apache-2.0 license.
Team
This project is brought to you by Addy Osmani and Anton Karlovskiy.