0.3.6 • Published 2 years ago

@postinumero/use-async v0.3.6

Weekly downloads
3
License
ISC
Repository
github
Last release
2 years ago

@postinumero/use-async

Create a suspending hook from an async function, an async generator or a function that returns an async iterator.

  • Server-side rendering
  • recall function for re-executing the function and rerendering related components from anywhere

Examples

Get data using axios

import { Suspense } from 'react';
import { create } from '@postinumero/use-async';
import axios from 'axios';

const [useAxios] = create(axios);

function Todo({ id }) {
  const { data } = useAxios(`https://jsonplaceholder.typicode.com/todos/${id}`);

  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

function App() {
  return (
    <Suspense fallback="Loading...">
      <Todo id="1" />
    </Suspense>
  );
}

Render timestamps with setInterval

import { Suspense } from 'react';
import { create } from '@postinumero/use-async';
import { Repeater } from '@repeaterjs/repeater';

const [useTimestamp] = create(
  () =>
    new Repeater(async (push, stop) => {
      push(Date.now());
      const interval = setInterval(() => push(Date.now()), 1000);
      await stop;
      clearInterval(interval);
    })
);

function Timestamp() {
  return <div>Timestamp: {useTimestamp()}</div>;
}

function App() {
  return (
    <Suspense fallback="Loading...">
      <Timestamp />
    </Suspense>
  );
}

API

create(fn[, config])

For creating shortcut functions of the rest of the API, without needing to pass fn and config each time.

Params

  • fn: AsyncFunction
  • config: Config (optional)

Returns

An array of functions [useAsync, recall, useAsyncSafe]. Each of the returned function take just the ...args as its arguments.

useAsync(fn[, config[, args]])

Params

  • fn: AsyncFunction
  • config: Config (optional)
  • args: arguments[] for fn (optional)

Returns

Resolved value of fn(...args).

Throws

A thrown exception from fn or a promise for React Suspense.

useAsyncSafe(fn[, config[, args]])

Params

  • fn: AsyncFunction
  • config: Config (optional)
  • args: arguments[] for fn (optional)

Returns

An array [error, value], where error is either null or a thrown exception from fn(...args), and value is resolved value of fn(...args).

Throws

Promise for React Suspense.

recall(fn[, config[, args]]) (async)

If there are components currently mounted using any of the hooks and the same arguments (fn, config, args), fn(...args) gets called. When fn resolves, components will rerender with the new value.

Params

  • fn: AsyncFunction
  • config: Config (optional)
  • args: arguments[] for fn (optional)

Returns

Resolves with undefined, when fn(...args) resolves.

Config

PropExampleDefault valueDescription
id"axios"undefinedCache values using id as key instead of fn. Required in SSR.

Server-side Rendering

  1. Use createSSRCache to get SSRCacheProvider and ssrData
  2. Wrawp server-side <App> with <SSRCacheProvider>
  3. Use react-ssr-prepass to handle suspsense
  4. Get initial SSR data using ssrData(). ssrData accepts a map function, which is called for each data entry with 2 arguments: data, { id, args }.
  5. Place the data in a <script> before the application
import { /* nothing, */ createSSRCache } from '@postinumero/use-async';
import ssrPrepass from 'react-ssr-prepass';

//...

const { ssrData, SSRCacheProvider } = createSSRCache();

const element = (
  <SSRCacheProvider>
    <App />
  </SSRCacheProvider>
);
await ssrPrepass(element);

const app = ReactDOMServer.renderToString(element);

res.send(
  html.replace(
    '<div id="root"></div>',
    `<script>${ssrData(([error, response]) =>
      // error ? nothing :
      [
        error,
        response && {
          data: response.data,
          headers: response.headers,
          status: response.status,
        },
      ]
    )}</script><div id="root">${app}</div>`
  )
);

Not ready for Suspense?

Import from @postinumero/use-async/loading-state to use the { isLoading, data, error } style API. Example:

import { create } from '@postinumero/use-async/loading-state';
import axios from 'axios';

const [, , useAxiosSafe] = create(axios);

function User({ id }) {
  const { isLoading, data, error } = useAxiosSafe(`/api/users/${id}`);

  if (isLoading) {
    return 'Loading...';
  }

  return <div>First name: {data.data.first_name}</div>;
}