nitish24p / react-adaptive-hooks

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

React Adaptive Loading Hooks · 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 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 can help you give users a great experience best suited to their device and network constraints.

Installation

npm i react-adaptive-hooks --save

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 can be found below.

Network

useNetworkStatus React hook for getting 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>;
};

Save Data

useSaveData React hook for getting Save Data whether it's Lite mode enabled or not

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>
  );
};

CPU Cores / Hardware Concurrency

useHardwareConcurrency React hook for getting the number of logical CPU processor cores of 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>
  );
};

Memory

useMemoryStatus React hook for getting memory status of the device

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>
  );
};

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 users 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'));

function 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} alt='product' {...rest} />
);

export default Light;

Full.js:

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

const Heavy = ({ 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(() => {
  return new Promise(resolve => {
    navigator.connection ? resolve(navigator.connection.effectiveType) : resolve(null)
  }).then((effectiveType) => {
    switch (effectiveType) {
      case "3g":
        return import(/* webpackChunkName: "light" */ "./light.js");
        break;
      case "4g":
        return import(/* webpackChunkName: "full" */ "./full.js");
        break;
      default:
        return import(/* webpackChunkName: "full" */ "./full.js")
    }
  });
});

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Suspense fallback={<div>Loading...</div>}>
          <Component />
        </Suspense>
      </header>
    </div>
  );
}

export default App;

Browser Support

Demos

Network

Save Data

CPU Cores / Hardware Concurrency

Memory

References

License

Licensed under the Apache-2.0 license.

Team

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

About

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

License:Apache License 2.0


Languages

Language:JavaScript 100.0%