Sign Up for Free

RunKit +

Try any Node.js package right in your browser

This is a playground to test code. It runs a full Node.js environment and already has all of npm’s 1,000,000+ packages pre-installed, including use-suspensible with all npm packages installed. Try it out:

require("react/package.json"); // react is a peer dependency. require("react-dom/package.json"); // react-dom is a peer dependency. var useSuspensible = require("use-suspensible")

This service is provided by RunKit and is not affiliated with npm, Inc or the package authors.

use-suspensible v0.2.3

A React hook that can make any data suspensible.

use-suspensible

npm-version Build Status Coverage Status

Commitizen friendly Conventional Commits JavaScript Style Guide code style: prettier

use-suspensible

React hooks that can make any data suspensible.

Why?

This is a proof-of-concept for using Suspense with non-promise based async libraries. Also see observable-hooks on implementing Render-as-You-Fetch pattern with Suspense and Rxjs Observable.

Installation

yarn

yarn add use-suspensible

npm

npm install --save use-suspensible

Usage

import React, { Suspense, useState, useEffect } from 'react'
import { useSuspensible } from 'use-suspensible'

function fetchData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({ content: "content" })
    }, 3000)
  })
}

const App = () => {
  const [data, setData] = useState()
  useEffect(
    () => {
      fetchData().then(setData)
    },
    []
  )

  return (
    <Suspense fallback={<h1>Loading...</h1>}>
      <Content data={data} />
    </Suspense>
  )
}

function Content({ data }) {
  useSuspensible(data)
  return (
    <h1>{data.content}</h1>
  );
}

Default trigger Suspense on null or undefined.

useSuspensible(data)

Custom comparison for checking finish state.

useSuspensible(data, data => data.status === 'finish')

You can have any number of useSuspensible in a Component.

useSuspensible(data1)
useSuspensible(data2)
useSuspensible(data3, data => data.status === 'finish')

return (
  <>
    <h1>{data1.content}</h1>
    <h1>{data2.content}</h1>
    <h1>{data3.content}</h1>
  </>
)

TypeScript >= 3.7

interface StatePending {
  status: 'pending'
  value: null
}

interface StateFinish {
  status: 'finish'
  value: number
}

type States = StatePending | StateFinish

//....

useSuspensible(
  data,
  (data: States): data is StateFinish => data.status === 'finish'
)

// Now data is of `StateFinish` type.

Beware

Due to the design of Suspense, each time a suspender is thrown, the children of Suspense Component will be destroyed and reloaded. Do not initialize async data and trigger Suspense in the same Component.

import React, { Suspense, useState, useEffect } from 'react'
import { useSuspensible } from 'use-suspensible'

function fetchData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({ content: "content" })
    }, 3000)
  })
}

const App = () => {
  return (
    <Suspense fallback={<h1>Loading...</h1>}>
      <Content />
    </Suspense>
  )
}

function Content({ data }) {
  const [data, setData] = useState()
  // This will cause infinite update.
  useEffect(
    () => {
      fetchData().then(setData)
    },
    []
  )
  useSuspensible(data)
  return (
    <h1>{data.content}</h1>
  );
}

Metadata

RunKit is a free, in-browser JavaScript dev environment for prototyping Node.js code, with every npm package installed. Sign up to share your code.
Sign Up for Free