Coder Social home page Coder Social logo

monzter50 / react-adaptive-hooks Goto Github PK

View Code? Open in Web Editor NEW

This project forked from midudev/react-adaptive-hooks

0.0 1.0 0.0 225 KB

Deliver experiences best suited to a user's device and network constraints

License: Apache License 2.0

JavaScript 100.00%

react-adaptive-hooks's Introduction

React Adaptive Loading Hooks & Utilities · Build Status npm bundle size

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:

import { useNetworkStatus } from 'react-adaptive-hooks/network';
import { useSaveData } from 'react-adaptive-hooks/save-data';
import { useHardwareConcurrency } from 'react-adaptive-hooks/hardware-concurrency';
import { useMemoryStatus } from 'react-adaptive-hooks/memory';

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)

import React from 'react';

import { useNetworkStatus } from 'react-adaptive-hooks/network';

const MyComponent = () => {
  const { effectiveConnectionType } = useNetworkStatus();

  let media;
  switch(effectiveConnectionType) {
    case 'slow-2g':
      media = <img src='...' alt='low resolution' />;
      break;
    case '2g':
      media = <img src='...' alt='medium resolution' />;
      break;
    case '3g':
      media = <img src='...' alt='high resolution' />;
      break;
    case '4g':
      media = <video muted controls>...</video>;
      break;
    default:
      media = <video muted controls>...</video>;
      break;
  }
  
  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 component
const initialEffectiveConnectionType = '4g';
const { effectiveConnectionType } = useNetworkStatus(initialEffectiveConnectionType);

Save Data

useSaveData utility for adapting based on the user's browser Data Saver preferences.

import React from 'react';

import { useSaveData } from 'react-adaptive-hooks/save-data';

const MyComponent = () => {
  const { saveData } = useSaveData();
  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 component
const initialSaveDataStatus = true;
const { saveData } = useSaveData(initialSaveDataStatus);

CPU Cores / Hardware Concurrency

useHardwareConcurrency utility for adapting to the number of logical CPU processor cores on the user's device.

import React from 'react';

import { useHardwareConcurrency } from 'react-adaptive-hooks/hardware-concurrency';

const MyComponent = () => {
  const { numberOfLogicalProcessors } = useHardwareConcurrency();
  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)

import React from 'react';

import { useMemoryStatus } from 'react-adaptive-hooks/memory';

const MyComponent = () => {
  const { deviceMemory } = useMemoryStatus();
  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 component
const initialMemoryStatus = { deviceMemory: 4 };
const { deviceMemory } = useMemoryStatus(initialMemoryStatus);

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:

import React, { Suspense, lazy } from 'react';

import { useNetworkStatus } from 'react-adaptive-hooks/network';

const Full = lazy(() => import(/* webpackChunkName: "full" */ './Full.js'));
const Light = lazy(() => import(/* webpackChunkName: "light" */ './Light.js'));

const MyComponent = () => {
  const { effectiveConnectionType } = useNetworkStatus();
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        { effectiveConnectionType === '4g' ? <Full /> : <Light /> }
      </Suspense>
    </div>
  );
};

export default MyComponent;

Light.js:

import React from 'react';

const Light = ({ imageUrl, ...rest }) => (
  <img src={imageUrl} {...rest} />
);

export default Light;

Full.js:

import React from 'react';
import Magnifier from 'react-magnifier';

const Full = ({ imageUrl, ...rest }) => (
  <Magnifier src={imageUrl} {...rest} />
);

export default Full;

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).

import React, { Suspense } from 'react';

const Component = React.lazy(() => {
  const effectiveType = navigator.connection ? navigator.connection.effectiveType : null

  let module;
  switch (effectiveType) {
    case '3g':
      module = import(/* webpackChunkName: "light" */ './Light.js');
      break;
    case '4g':
      module = import(/* webpackChunkName: "full" */ './Full.js');
      break;
    default:
      module = import(/* webpackChunkName: "full" */ './Full.js');
      break;
  }

  return module;
});

const App = () => {
  return (
    <div className='App'>
      <Suspense fallback={<div>Loading...</div>}>
        <Component />
      </Suspense>
    </div>
  );
};

export default App;

Browser Support

Demos

Network

Save Data

CPU Cores / Hardware Concurrency

Memory

Hybrid

References

License

Licensed under the Apache-2.0 license.

Team

This project is brought to you by Addy Osmani and Anton Karlovskiy.

react-adaptive-hooks's People

Contributors

addyosmani avatar anton-karlovskiy avatar eugeneglova avatar midudev avatar mlampedx avatar mobily avatar mudssrali avatar stramel avatar wmertens avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.