Rest Hooks

Async State Management without the Management

README

Reactive Data Client


Define your async methods. Use them synchronously in React. Instantly mutate the data and automatically update all usages.

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


Simple TypeScript definition


  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. ```

Create collection of API Endpoints


  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. ```

Subscriptions


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

Type-safe Imperative Actions


  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. ```

Programmatic queries


  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. ```

Powerful Middlewares


  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. ```

Integrated data mocking


  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