Rest Hooks

Async State Management without the Management

README

Reactive Data Client


Installation


  1. ```bash
  2. npm install --save @data-client/react @data-client/rest @data-client/test @data-client/hooks
  3. ```

For more details, see the Installation docs page.

Usage



  1. ```typescript
  2. class User extends Entity {
  3.   id = '';
  4.   username = '';

  5.   pk() {
  6.     return this.id;
  7.   }
  8. }

  9. class Article extends Entity {
  10.   id = '';
  11.   title = '';
  12.   body = '';
  13.   author = User.fromJS();
  14.   createdAt = Temporal.Instant.fromEpochSeconds(0);

  15.   pk() {
  16.     return this.id;
  17.   }

  18.   static schema = {
  19.     author: User,
  20.     createdAt: Temporal.Instant.from,
  21.   };
  22. }
  23. ```


  1. ```typescript
  2. const UserResource = createResource({
  3.   path: '/users/:id',
  4.   schema: User,
  5.   optimistic: true,
  6. });

  7. const ArticleResource = createResource({
  8.   path: '/articles/:id',
  9.   schema: Article,
  10.   searchParams: {} as { author?: string },
  11.   optimistic: true,
  12.   paginationField: 'cursor',
  13. });
  14. ```

One line data binding


  1. ```tsx
  2. const article = useSuspense(ArticleResource.get, { id });
  3. return (
  4.   <article>
  5.     <h2>
  6.       {article.title} by {article.author.username}
  7.     </h2>
  8.     <p>{article.body}</p>
  9.   </article>
  10. );
  11. ```


  1. ```tsx
  2. const ctrl = useController();
  3. return (
  4.   <CreateProfileForm
  5.     onSubmit={data => ctrl.fetch(UserResource.getList.push, { id }, data)}
  6.   />
  7.   <ProfileForm
  8.     onSubmit={data => ctrl.fetch(UserResource.update, { id }, data)}
  9.   />
  10.   <button onClick={() => ctrl.fetch(UserResource.delete, { id })}>Delete</button>
  11. );
  12. ```


  1. ```tsx
  2. const price = useLive(PriceResource.get, { symbol });
  3. return price.value;
  4. ```


  1. ```tsx
  2. const ctrl = useController();
  3. ctrl.expireAll(ArticleResource.getList);
  4. ctrl.invalidate(ArticleResource.get, { id });
  5. ctrl.invalidateAll(ArticleResource.getList);
  6. ctrl.setResponse(ArticleResource.get, { id }, articleData);
  7. ctrl.fetch(ArticleResource.get, { id });
  8. ```


  1. ```tsx
  2. const queryTotalVotes = new Query(
  3.   new schema.All(Post),
  4.   (posts, { userId } = {}) => {
  5.     if (userId !== undefined)
  6.       posts = posts.filter(post => post.userId === userId);
  7.     return posts.reduce((total, post) => total + post.votes, 0);
  8.   },
  9. );

  10. const totalVotes = useCache(queryTotalVotes);
  11. const totalVotesForUser = useCache(queryTotalVotes, { userId });
  12. ```


  1. ```ts
  2. class LoggingManager implements Manager {
  3.   getMiddleware = (): Middleware => controller => next => async action => {
  4.     console.log('before', action, controller.getState());
  5.     await next(action);
  6.     console.log('after', action, controller.getState());
  7.   };

  8.   cleanup() {}
  9. }
  10. ```


  1. ```tsx
  2. const fixtures = [
  3.   {
  4.     endpoint: ArticleResource.getList,
  5.     args: [{ maxResults: 10 }] as const,
  6.     response: [
  7.       {
  8.         id: '5',
  9.         title: 'first post',
  10.         body: 'have a merry christmas',
  11.         author: { id: '10', username: 'bob' },
  12.         createdAt: new Date(0).toISOString(),
  13.       },
  14.       {
  15.         id: '532',
  16.         title: 'second post',
  17.         body: 'never again',
  18.         author: { id: '10', username: 'bob' },
  19.         createdAt: new Date(0).toISOString(),
  20.       },
  21.     ],
  22.   },
  23.   {
  24.     endpoint: ArticleResource.update,
  25.     response: ({ id }, body) => ({
  26.       ...body,
  27.       id,
  28.     }),
  29.   },
  30. ];

  31. const Story = () => (
  32.   <MockResolver fixtures={options[result]}>
  33.     <ArticleList maxResults={10} />
  34.   </MockResolver>
  35. );
  36. ```

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


For the small price of 9kb gziped.    🏁Get started now

Features


- [x] TS Strong Typescript inference
- [x] 🛌 React Suspense support
- [x] 🧵 React 18 Concurrent mode compatible
- [x] 🎣 Declarative API
- [x] 📝 Composition over configuration
- [x] 💰 Normalized caching
- [x] 💥 Tiny bundle footprint
- [x] 🛑 Automatic overfetching elimination
- [x] 🧘 Flexible to fit any API design (one size fits all)
- [x] 🔧 Debugging and inspection via browser extension
- [x] 🌳 Tree-shakable (only use what you need)
- [x] 🔁 Subscriptions
- [x] ♻️ Optional redux integration
- [x] 📱 React Native support
- [x] ⚛️ NextJS support
- [x] 💽 Global data consistency guarantees
- [x] 🏇 Automatic race condition elimination
- [x] 👯 Global referential equality guarantees