Delightful data fetching for React.

Overview

๐Ÿ›Œ๐ŸŽฃ Rest hooks

CircleCI Coverage Status npm downloads bundle size npm version PRs Welcome Chat

Asynchronous dynamic data at scale. Performance, data integrity, and typing for REST, proto, GraphQL, websockets and more.

๐ŸŒŽ Website

Simple TypeScript definition

class ArticleResource extends Resource {
  readonly id: string = '';
  readonly title: string = '';
  readonly body: string = '';

  pk() {
    return this.id;
  }
  static urlRoot = '/articles/';
}

One line data hookup

const article = useResource(ArticleResource.detail(), { id });
return (
  <>
    <h2>{article.title}</h2>
    <p>{article.body}</p>
  </>
);

Mutation

const { fetch } = useController();
return (
  <ArticleForm
    onSubmit={data => fetch(ArticleResource.update(), { id }, data)}
  />
);

And subscriptions

const price = useResource(PriceResource.detail(), { symbol });
useSubscription(PriceResource.detail(), { symbol });
return price.value;

...all typed ...fast ...and consistent

For the small price of 8kb gziped.    ๐Ÿ Get started now

Features

Principals of Rest Hooks

TS Integrity

  • Strong inferred types
  • Global referential equality guarantees
  • Normalized store creates a single source of truth
  • Strong invariants robust against race conditions
  • Validation

Performance

  • Stale While Revalidate configurable cache
  • Only re-render

Composition over configuration

  • Declarative data definitions
  • Decoupled API definitions from usage
  • Co-located data dependencies
    • Centralized orchestration
  • Extensible orchestration through Managers (middleware)
  • Composable hooks
    • subject pattern
  • Suspense + concurrent mode async orchestration

Incremental Adoption

  • Simple case is simple
  • Scale as your app scales

Special thanks

Thanks to @0xcaff, @melissafzhang and @alexiswolfish for their valuable feedback.

Issues
  • Request for more examples: Adding authentication header to every request

    Request for more examples: Adding authentication header to every request

    I'm new to Rest Hooks, so please forgive me if I'm overlooking something obvious. I'm trying to figure out what's the best way of enhancing all requests (fetch, mutations, etc.) with a custom Authorization-Token header.

    I have an <AuthenticationProvider> context provider that works with a useAuthContext hook like this:

    const MyApp = () => (
      <AuthenticationProvider>
        <CacheProvider>
          ... // the app
        </CacheProvider>
      </AuthenticationProvider>
    );
    

    And then in one of my screens I can access the session and access token like this:

    const MyScreen = ({ id }: { id: number }) => {
      const { session } = useAuthContext();
      const fetchUser = useResource(PostResource.detailShape(), { id });
      return ( ... );
    }
    

    I'm having trouble understanding how I can pass the sesion.accessToken to my resource on every fetch. I've walked through the documentation and found various pointers such as writing a custom Manager, using fetchOptionsPlugin or implementing a custom Resource. I also considered creating my own useAuthResource() hook. However, I fail to understand how all these pieces exactly fit together to achieve what I'm trying to do: Set an Access-Token HTTP header on all outgoing requests based on the value of session.accessToken.

    Describe the solution you'd like Ideally I would want to configure the CacheProvider (or create my own implementation if necessary) that is aware of the authentication context and automatically sets the Access-Token HTTP header if logged in.

    It would be great if there would be some additional examples for how to use rest-hooks in real-world applications. Overall the documentation is good and helpful, but I simply don't see how everything fits together yet.

    enhancement 
    opened by arabold 35
  • Infinite scroll example

    Infinite scroll example

    Have some example to implement infinite scroll?

    enhancement 
    opened by elsangedy 27
  • Compatibility with preact

    Compatibility with preact

    React version (preact 10.5.12)

    Concurrent mode no

    Rest Hooks version (e.g., 5.0.6)

    Describe the bug (This is rather a feature request but IMO it's more appropriate to use bug template) This package seems to not work with Preact (alternative to React with compatible API).

    Problem comes up when wrapping an application with <CacheProvider>. Engine stops rendering any children and what's unfortunate doesn't show any errors.

    Small hint is that ot does render when I remove context providers and keep just {children} in https://github.com/coinbase/rest-hooks/blob/e1e353dfc64725c79ab99bb6a0c85114399c6dfc/packages/core/src/react-integration/provider/CacheProvider.tsx#L56-L64

    To Reproduce Steps to reproduce the behavior:

    1. Create new codesandbox with Preact template
    2. Add @rest-hooks/rest & rest-hooks to dependencies
    3. Add import { CacheProvider } from 'rest-hooks'; to src/index.js
    4. Wrap App by CacheProvider
    5. Problem: Rendered output disappears

    Or check codesandbox example

    Expected behavior Package works with Preact just as it would with React

    Additional context No console errors.

    bug 
    opened by piotr-cz 24
  • Compositional parallel suspense

    Compositional parallel suspense

    useAll() - like Promise.all() for suspense

    const [article, users, post] = useAll(
      () => useResource(CoolerArticleResource.detail(), id),
      () => useResource(UserResource.list()),
      () => useResource(Post.detail(), { id }),
    );
    

    Why

    Currently one can do parallel requests with useResource() by sending variable tuples of normal useResource() arguments.

    const [article, users, post] = useResource(
      [CoolerArticleResource.detail(), id],
      [UserResource.list()],
      [Post.detail(), { id }],
    );
    

    This is problematic for various reasons

    • Not very discoverable
    • Makes typing arguments very complicated and obfuscates the errors when types are enforced
    • Makes composition of useResource() very challenging
    • Doesn't integrate with other suspense hooks one could potentially use - thereby reducing parallelism potential
    • Isn't obvious that changing the number of arguments is not supported
    • Polymorphic function calls can be confusing to developers, as well as compilers - potentially limiting optimizations.

    Legacy

    We can continue supporting useResource() with multiargs, and simply update docs to suggest using this method instead until some long later date where we remove it.

    Upgrading should be trivial since it can be fully done with a regex. Should be publish regex?

    Alternatives

    Instead of wrapping suspending hooks, we could turn any Suspendable into suspense:

    interface Suspendable<T> {
      then: (dat: T) => void;
      key(): string;
    }
    
    const [article, users, post] = useAwait(
      useResource(CoolerArticleResource.detail(), id),
      useResource(UserResource.list()),
      useResource(Post.detail(), { id }),
    );
    

    But useResource() will only return a promise, so to use it in singular case:

    const article = useAwait(useResource(CoolerArticleResource.detail(), id));
    

    Also allows suspending useRetrieve():

    const article = useAwait(useRetrieve(CoolerArticleResource.detail(), id));
    

    This could be specialized, but then can't have variable args:

    const awaitResource = (...args) => useAwait(useResource(...args));
    
    const article = awaitResource(CoolerArticleResource.detail(), id));
    

    'await' prefix can be added to eslint rules of hooks so they are enforced

    Pros:

    • Allows easy usage with useRetrieve() to not subscribe to state
    • Distinguishes suspense in a clear manner
    • Interops with anything that can return a promise

    Cons:

    • Common case is more verbose
    • Legacy is not as easy to support
    • Doesn't interop with other suspending libraries
    enhancement 
    opened by ntucker 24
  • Partial update optimism not working for singleton resource

    Partial update optimism not working for singleton resource

    React version 16.11.0

    Concurrent mode no

    Describe the bug Optimism is not working on partialUpdateShape for a singleton resource.

    To Reproduce

    I have a singleton resource implemented as such:

    export class MySingletonResource extends Resource {
      static urlRoot = "/singleton";
    
      pk() {
        return "MySingletonResource";
      }
    
      static url<T extends typeof Resource>(this: T) {
        return this.urlRoot;
      }
    
      readonly myProperty: boolean = false;
    }
    

    When I do:

    const data = useResource(MySingletonResource.detailShape(), {});
    const update = useFetcher(MySingletonResource.partialUpdateShape());
    update({}, { myProperty: true });
    

    I have to wait for the network request to finish before a rerender with the updated data (myProperty is true) is triggered. This delay is very noticeable.

    Expected behavior I would expect the partial update to be applied instantaneously, instead of needing to wait for the network request to finish.

    bug 
    opened by yunyu 23
  • How to deal with resources without pk?

    How to deal with resources without pk?

    Is your feature request related to a problem? Please describe.

    Say we want to represent some singleton-like resource, e.g. oauth service connection. Such things do not have any kind of primary key somewhere in them, there's just one instance of them anyway. How to model such things as a resource?

    Currently I have end up this snippet, but this seems not to work with deleting, ending up with Error: Resource not found GET /api/service/connect:

    export default class ServiceConnection extends Resource {
      readonly user: User | null = null;
    
      pk() {
        return 1;
      }
    
      static urlRoot = '/api/service/connect';
    
      static url() {
        return ServiceConnection .urlRoot;
      }
    }
    

    Describe the solution you'd like

    Personally I expected this to work by intuition:

    export default class ServiceConnection extends Resource {
      readonly user: User | null = null;
    
      pk() {
        return null;
      }
    
      static urlRoot = '/api/service/connect';
    }
    

    Notes

    I could not find any information about this in the docs. Also I could not find what does pk returning null mean. Either this information looks to be quite hard to find in docs or is just absent :(

    enhancement 
    opened by mkaput 18
  • Expose APIs for persisting RestProvider state

    Expose APIs for persisting RestProvider state

    Is your feature request related to a problem? Please describe. I'm exploring how to persist <RestProvider /> state between reloads, using localStorage. Unfortunately this provider does not have a way to inform users its state has changed. I managed to get it working via __INTERNAL__.StateContext, but there should be a public API for this.

    Describe the solution you'd like Add a new onStateChange (or similar) prop to <RestProvider/>. Alongside initialState this new prop would allow full customization of the hydration & dehydration logic.

    Introducing a cacheManager prop with the following signature could work as well:

    interface CacheManager<T> {
      save: (state: State<T>) => void;
      load: () => State<T> | undefined;
    }
    

    Not sure how the initialState would behave in this case though.

    Describe alternatives you've considered I've successfully implemented this feature via the redux integration, but I feel like I shouldn't have to bring redux for this specific use case.

    enhancement 
    opened by sylvaingi 17
  • Using Multiple resources crashes chrome

    Using Multiple resources crashes chrome

    React version 16.8.6

    Concurrent mode no

    Describe the bug Passing multiple resources to useResource crashes chrome sometimes

    To Reproduce Steps to reproduce the behavior:

    1. Go to https://rest-hooks-w44uh8.stackblitz.io/multiple
    2. Click on the menu item multiple
    3. Sometimes it will show "10, 11" sometimes the tab will crash
    4. Refresh the page, will crash usually within a few refreshes

    Expected behavior A clear and concise description of what you expected to happen. It shouldn't crash.

    Switching to the other method will mean it never crashes https://stackblitz.com/edit/rest-hooks-w44uh8?file=issues%2FMultipleResources.tsx

    bug 
    opened by blanchg 16
  • Type error when using Resource.detail() but not when using detailShape()

    Type error when using Resource.detail() but not when using detailShape()

    React version 17.0.1

    Concurrent mode no

    Rest Hooks version 5.0.5

    TypeScript version 4.1.5

    Describe the bug I recieve a type error when using Resource.detail() but not when using detailShape(). The typings indicate that this method is deprecated but I am following along with the Getting Started guide.

    Apologies if I have missed this issue being raised already or something glaringly obvious. I did have a good hunt round for this on the Repo.

    To Reproduce Steps to reproduce the behavior:

    1. Set up example on getting started using latest React and rest-hooks.
    2. Observe type error when using const article = useResource(ArticleResource.detail(), { id });
    3. Type error dissapears if method changed to const article = useResource(ArticleResource.detailShape(), { id });

    Additional context TS error recieved

    (alias) class ArticleResource import ArticleResource No overload matches this call. Overload 1 of 17, '(v1: readonly [ReadShape<any, any, any>, any], v2: readonly [ReadShape<any, any, any>, any]): [any, any]', gave the following error. Argument of type 'Pick<{ schema: SchemaDetail<ArticleResource>; }, never> & Pick<EndpointInstance<(this: EndpointInstance<FetchFunction<any, any, any>, string | { ...; } | Schema[] | SchemaSimple<...> | Serializable<...>, true> & { ...; }, params: any) => Promise<...>, undefined, undefined> & { ...; }, "url" | ... 4 more ... | "getFe...' is not assignable to parameter of type 'readonly [ReadShape<any, any, any>, any]'. Overload 2 of 17, '(fetchShape: ReadShape<any, any, any>, params: { id: number; }): any', gave the following error. Argument of type 'Pick<{ schema: SchemaDetail<ArticleResource>; }, never> & Pick<EndpointInstance<(this: EndpointInstance<FetchFunction<any, any, any>, string | { ...; } | Schema[] | SchemaSimple<...> | Serializable<...>, true> & { ...; }, params: any) => Promise<...>, undefined, undefined> & { ...; }, "url" | ... 4 more ... | "getFe...' is not assignable to parameter of type 'ReadShape<any, any, any>'. Types of property 'type' are incompatible. Type '"mutate"' is not assignable to type '"read"'.ts(2769)

    bug 
    opened by C94P 15
  • After cache is cleared, some resources are never re-fetched

    After cache is cleared, some resources are never re-fetched

    React version (e.g., 16.8.5) 16.13.1

    Concurrent mode yes/no no

    Rest Hooks version (e.g., 4.5.9) 4.5.9

    Describe the bug After resetting the cache (using useResetter()), some resources get stuck in a state where they are never refetched, causing any component that depends on them (using useResource()) to be stuck in suspense mode.

    To Reproduce Steps to reproduce the behavior:

    1. Attempt to load a slow-loading resource using useResource().
    2. While this resource is loading, reset the cache using useResetter().
    3. Attempt to load the same resource again.
    4. Observe the component stuck in suspense.

    Expected behavior In step 3, the resource should be re-fetched.

    Additional context I'm guessing it has to do with this line. The promise is indeed already present in this.fetched, but it's rejected: context

    So I'm assuming something in the network manager cleanup should be removing this, or the line referenced above should be checking to see if the promise is still pending, not just if it's present.

    Hopefully this is enough info to track down the bug (or tell me what I'm doing wrong), but if not I can try to create a minimal example to reproduce this.

    Thanks for an awesome library!

    bug 
    opened by michael-swarm 15
  • feat: Validate everything

    feat: Validate everything

    Fixes # .

    Motivation

    Solution

    Open questions

    opened by ntucker 1
  • For Svelte too?

    For Svelte too?

    I would very much like to hear that there is a version of this splendid project for Svelte! I beg you! Tell me it exists!

    enhancement 
    opened by frederikhors 6
  • Handling poor / no internet connection

    Handling poor / no internet connection

    Hi all,

    Not marking this as a bug as potentially just my own misunderstanding of the docs. In brief, Iโ€™m struggling gracefully failing if internet connection drops out and an update is triggered.

    I have a resource as such:

    import request from "superagent";
    
    export default class EntryResource extends Resource {
      readonly UserCode: string | undefined = undefined;
    
      static async fetch<T extends typeof Resource>(
        this: T,
        method: Method = "get",
        url: string,
        body?: Readonly<object | string>
      ) {
        const req = request[method](url);
        return req
          .then((res) => {
            if (res.body.items) return res.body.items;
            if (res.body.status === "fail") return [];
            else return res.body.codes;
          })
      }
    
      static update<T extends typeof Resource>(this: T) {
        return {
          ...this.updateShape(),
          options: {
            ...this.getFetchOptions(),
            optimisticUpdate: (params: any, body: any) => ({
              ...body,
              otherKeys: etc,
            }),
          },
        };
      }
    
      pk() {
        return this.etc;
      }
    
      static urlRoot = `etc`;
    }; 
    

    And Iโ€™m wrapping the various components in suspense and NetworkErrorBoundarys.

    <Suspense fallback={<Loading />}>
                    <NetworkErrorBoundary fallbackComponent={ErrorPage}>
    			<Component /> (which uses the resource above)
                    </NetworkErrorBoundary>
     </Suspense>
    

    The resource works fine until there is an internet connection dropout. At this point the NetwrokErrorBoundary seems to be missed, leading to displaying the suspenseโ€™s loading spinner infinitely.

    The behaviour Iโ€™d preferably like would be to cache the update data and try to send it again when there is an internet connection. Failing that, Iโ€™d like to stop attempting the update/PUT and display a no internet connection popup, keeping displaying the data before the update call. Iโ€™ve had no joy catching the error in the fetch and returning something to trigger an error as this breaks the expected data shape. Overall, Iโ€™m unsure if this behaviour (specifically missing the NetworkErrorBoundary) is expected and therefore is or isnโ€™t a bug. Can anyone please advise on this or on my wider aims of handling this specific error?

    opened by Murray2015 2
  • Use an existing class for a resource

    Use an existing class for a resource

    Hello,

    I have a normal class, can I use it to create a resource? Something like this?

    export class Demo {
      id: number,
      value: string
    }
    
    export default class DemoResource extends Resource<Demo> {
     
      pk() {
        return this.id?.toString();
      }
    
      static urlRoot = 'http://test.com/demo/';
    }
    
    enhancement 
    opened by lucasdidur 1
  • OpenAPI generator for rest hooks?

    OpenAPI generator for rest hooks?

    Hi, Iโ€™m evaluating rest-hooks for a new project. We already use OpenAPI/Swagger. Does it sound like a good idea to write an OpenAPI generator to transform the OpenAPI definitions into rest-hooks resource definitions? That way thereโ€™d be a single source of truth for all things API. Has anyone had a similar setup? Did it work? Do you think it could work? Thank you for your answers!

    enhancement 
    opened by AndrewPrifer 4
  • [docs] Websockets example

    [docs] Websockets example

    Describe the solution you'd like

    • Custom manager.
    • Shows connection, disconnection lifecycles.
    • Shows intercepting sub/unsub actions
    • Shows dispatching receives on message pushes
    enhancement 
    opened by ntucker 0
Hook, simplifying dealing with Promises inside of React components

promise-hook Installation Install it with yarn: yarn add promise-hook Or with npm: npm i promise-hook --save Demo The simplest way to start playing

null 49 May 3, 2021
A delightful modal dialog component for React, built from the ground up to support React Hooks.

?? modali A delightful modal dialog library for React, built from the ground up to support React Hooks. Modali provides a simple interface to build be

Upmostly 196 Oct 19, 2021
React axios hooks for CRUD

WARNING: not maintained, feel free to fork and use in any way npm i axios use-axios-react Features Hooks for โœ… data fetching โœ… CRUD โœ… Batch operations

Sergey Sytsevich 26 Sep 12, 2021
A React hook compatible with React 16.6's Suspense component.

useFetch useFetch is a React hook that supports the React 16.6 Suspense component implementation. The design decisions and development process for thi

Charles Stover 488 Sep 8, 2021
Delightful data fetching for React.

Asynchronous dynamic data at scale. Performance, data integrity, and typing for REST, proto, GraphQL, websockets and more.

Coinbase 1.4k Oct 11, 2021
React hooks for handling auth stuff

use-eazy-auth React components and hooks to deal with token based authentication This project takes the main concepts and algorithms (but also the nam

INMAGIK srl 48 Jun 29, 2021
๐Ÿฆ• Deno, ESM + React: No build, no bundle, all streaming

Deno, ESM + React: No build, no bundle, all streaming Ultra is a web framework that leans hard into your browser's native features. Embrace the future

Exhibitionist 1.5k Oct 15, 2021
Async HTTP request data for axios. Designed for diverse UI states, SSR and data pre-caching.

React useApi() Axios-based React hooks for async HTTP request data. react-use-api feeds API data to React components when SSR (Server-Side Rendering),

Ryan 58 Jul 19, 2021
โš›๏ธ Hooks for fetching, caching and updating asynchronous data in React

Hooks for fetching, caching and updating asynchronous data in React Enjoy this library? Try the entire TanStack! React Table, React Form, React Charts

Tanner Linsley 23.2k Oct 14, 2021
React custom hooks for async functions with abortability and composability

react-hooks-async React custom hooks for async functions with abortability and composability Introduction JavaScript promises are not abortable/cancel

Daishi Kato 493 Oct 14, 2021
๐Ÿป Bear necessities for state management in React

A small, fast and scalable bearbones state-management solution using simplified flux principles. Has a comfy api based on hooks, isn't boilerplatey or opinionated.

Poimandres 11.3k Oct 20, 2021
A toolkit for opinionated use of the react-query + Jotai integration.

Jotai Query Toolkit (JQT) This is an opinionated toolkit for working with Jotai and react-query. This library extends upon the react-query integration

Fungible Systems 8 Oct 20, 2021
React hook to handle any async operation in React components, and prevent race conditions

React-async-hook This library only does one small thing, and does it well. Don't expect it to grow in size, because it is feature complete: Handle fet

Sรฉbastien Lorber 966 Oct 16, 2021
React hook library for managing cart state

react-use-cart ?? A lightweight shopping cart hook for React, Next.js, and Gatsby Why? No dependencies ?? Not tied to any payment gateway, or checkout

Jamie Barton 174 Oct 17, 2021
๐Ÿถ React hook for making isomorphic http requests

useFetch ?? React hook for making isomorphic http requests Main Documentation npm i use-http Features SSR (server side rendering) support TypeScript s

Ava 2k Oct 17, 2021
Dependency injection for React hooks

React Facade An experimental library that uses Proxy and TypeScript to create a strongly typed facade for your React hooks. Dependency inversion betwe

Gabe Scholz 59 Oct 13, 2021
๐Ÿถ React hook for making isomorphic http requests

useFetch ?? React hook for making isomorphic http requests Main Documentation npm i use-http Features SSR (server side rendering) support TypeScript s

Ava 2k Oct 17, 2021
Complex Loader Management Hook for React Applications

Complex Loader Management Hook for React. Read the Medium post "Managing Complex Waiting Experiences on Web UIs". react-wait is a React Hook helps to

Fatih Kadir Akฤฑn 289 Oct 18, 2021
๐ŸŽฃ Minimal hooks-first GraphQL client

graphql-hooks ?? Minimal hooks-first GraphQL client. Features ?? First-class hooks API โš–๏ธ Tiny bundle: only 7.6kB (2.8 gzipped) ?? Full SSR support: s

NearForm 1.6k Oct 11, 2021