oktanedeprecated

A light-weight and customizable library for data fetching in React

Usage no npm install needed!

<script type="module">
  import oktane from 'https://cdn.skypack.dev/oktane';
</script>

README

Oktane

npm package npm bundle size

Current status: ๐Ÿšง In alpha stage so expect breaking changes. Check out the roadmap for more info.

A light-weight and customizable library for data fetching in React.

Features

  • ๐Ÿ“ฆ Minimal footprint (< 3kb gzipped)
  • ๐ŸŒ Backend agnostic
  • ๐Ÿงน Automatic Garbage collection
  • ๐Ÿ”ซ Request cancellation
  • โซ Parallel / Dependent Queries
  • ๐Ÿ”ƒ Subscriptions / Lazy queries
  • ๐Ÿ”Œ Plugins support
  • ๐Ÿ’™ TypeScript ready
  • and more ...

Installation

Requires React v16.8.6 or higher

npm add oktane

Basic usage

Open in CodeSandbox

Creating the client

import { createClient, ClientProvider } from 'oktane';

const client = createClient({
  fetch: ({ query }) => {
    return fetch(
      `https://jsonplaceholder.typicode.com/${query}`
    ).then((res) => res.json());
  },
});

const App = () => (
  <ClientProvider value={client}>
    <Todos />
  </ClientProvider>
);

Fetching data

import { useQuery } from 'oktane';

const Todos = () => {
  const { data, status } = useQuery('todos');

  if (status === 'pending') {
    return <p>loading ...</p>;
  }

  return (
    <>
      <h2>Todo list</h2>
      <ul>
        {data.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </>
  );
};

How it works

Many data fetching libraries provide multiple React hooks to support use cases e.g. useSubscription, useInfiniteQuery ..etc. To minimize the API surface Oktane takes a different approach.

Here how someone would make a request using the useQuery hook provided by Oktane:

const { data, error, hasMore, fetchMore, ...rest } = useQuery(/* query */);

Note: useManualQuery hook works the same way as useQuery except it doesn't fetch the request automatically on mount/updates but rather exposes a helper to manually fetch when needed.

When resolving a request, Oktane checks the value returned by clientOptions.fetch(request, ctx) call and does one of the following based to the type:

  • Promise: (demo )
    • Waits for the Promise to resolve and then set data to the result.
    • In the case of error, Oktane will catch the error and expose it as error.
    • Calling hasMore will always return false.
    • Use case: API Calls, loading data from LocalStorage ...etc.
  • Iterable / Async Iterable: (demo )
    • Calls iterator.next() once and sets data to the result.
    • Next values can be emitted by calling fetchMore.
    • Calling hasMore will return true as long as the iterator doesn't complete.
    • In the case of error, Oktane will catch the error and expose it as error.
    • Use case: Infinite scroll.
  • Callback function: (demo )
    • Assumes a function that accepts a subscriber and optionally returns a function to close subscription (i.e. unsubscribe).
    • Any value passed to subscriber.next() will be available as data.
    • Calling subscriber.error() will set the value to error and close the subscription.
    • Calling subscriber.complete() will mark the request as completed and close the subscription.
    • Calling hasMore will always return false.
    • Use case: Anything you would use an Observable for e.g. Web Socket.
  • Anything else: wraps it in Promise.resolve and applies the Promise rule above.

It's worth mentioning that custom plugins may alter the behavior described above. For example, a plugin may decide not to report errors back to the React hook and instead retry the request every time it fails.

API

createClient

function createClient(options: ClientOptions): Client

Arguments

  • options (object)
    • fetch (function): The function that resolves all requests. Required.
    • plugins (array): An array of custom plugins.
    • cache (object)
      • disposeTime (number): A timeout for unused requests. Default is 30 seconds.

useQuery

function useQuery(query: QueryFunc  | any): {
  cancel: () => void;
  refetch: () => void;
  hasMore: () => boolean;
  fetchMore: () => void;
}

useManualQuery

function useManualQuery(query: any): {
  fetch: () => void;
  cancel: () => void;
  refetch: () => void;
  hasMore: () => boolean;
  fetchMore: () => void;
}

Examples

Check out the examples folder.

Credits

Inspired by the following great libraries:

  • Redux: Predictable state container for JavaScript apps.
  • SWR: React Hooks library for remote data fetching.
  • React Query: Hooks for fetching, caching, and updating asynchronous data in React.

License

MIT ยฉ Ahmed T. Ali