Convert Figma logo to code with AI

reactive logodata-client

Async State Management without the Management. REST, GraphQL, SSE, Websockets

1,928
93
1,928
5

Top Related Projects

42,139

🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.

30,395

React Hooks for Data Fetching

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.

The official, opinionated, batteries-included toolset for efficient Redux development

18,398

Relay is a JavaScript framework for building data-driven React applications.

Quick Overview

Reactive Data Client is a comprehensive data fetching and caching solution for React applications. It provides a powerful and flexible API for managing remote data, optimizing network requests, and maintaining a consistent state across the application. The library is designed to work seamlessly with REST, GraphQL, and other data sources.

Pros

  • Efficient caching and state management, reducing unnecessary network requests
  • Automatic request deduplication and optimistic updates for improved performance
  • Supports both REST and GraphQL APIs out of the box
  • Integrates well with TypeScript for enhanced type safety

Cons

  • Steeper learning curve compared to simpler data fetching libraries
  • Requires more setup and configuration for complex use cases
  • May be overkill for small projects or simple data fetching needs
  • Documentation could be more comprehensive for advanced features

Code Examples

  1. Defining an endpoint:
import { Endpoint } from '@data-client/endpoint';

const UserDetail = new Endpoint(({ id }: { id: number }) => ({
  url: `/users/${id}`,
  schema: User,
}));
  1. Using a hook to fetch data:
import { useResource } from '@data-client/react';

function UserProfile({ id }: { id: number }) {
  const user = useResource(UserDetail, { id });
  return <div>{user.name}</div>;
}
  1. Optimistic updates:
import { useFetcher } from '@data-client/react';

function UpdateUserButton({ user }: { user: User }) {
  const update = useFetcher(UserDetail);
  
  const handleClick = () => {
    update({ id: user.id }, { name: 'New Name' }, { optimisticUpdate: true });
  };

  return <button onClick={handleClick}>Update Name</button>;
}

Getting Started

  1. Install the package:
npm install @data-client/react @data-client/rest
  1. Set up the provider in your app:
import { CacheProvider } from '@data-client/react';
import { RestEndpoint } from '@data-client/rest';

function App() {
  return (
    <CacheProvider>
      {/* Your app components */}
    </CacheProvider>
  );
}
  1. Define endpoints and use hooks in your components:
import { Endpoint } from '@data-client/endpoint';
import { useResource } from '@data-client/react';

const UserList = new Endpoint(() => ({
  url: '/users',
  schema: [User],
}));

function UserListComponent() {
  const users = useResource(UserList);
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

Competitor Comparisons

42,139

🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.

Pros of Query

  • Wider adoption and larger community support
  • More comprehensive documentation and examples
  • Built-in devtools for easier debugging and visualization

Cons of Query

  • Potentially higher bundle size due to more features
  • Steeper learning curve for complex use cases
  • Less focus on normalized caching compared to Data Client

Code Comparison

Query:

const { data, isLoading, error } = useQuery('todos', fetchTodos)

if (isLoading) return 'Loading...'
if (error) return 'An error occurred: ' + error.message

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

Data Client:

const todos = useSuspense(TodoResource.getList())

return (
  <ul>{todos.map(todo => <li key={todo.id}>{todo.title}</li>)}</ul>
)

Summary

Query offers a more mature ecosystem with extensive documentation and community support, making it easier for developers to get started and find solutions. However, Data Client provides a more streamlined API for normalized caching and may be more suitable for projects requiring efficient data management. The choice between the two depends on specific project requirements and developer preferences.

30,395

React Hooks for Data Fetching

Pros of SWR

  • Simpler API with less boilerplate code
  • Built-in support for real-time data updates
  • Extensive documentation and large community support

Cons of SWR

  • Less flexible caching mechanism
  • Limited support for complex data normalization
  • Fewer advanced features for managing large-scale applications

Code Comparison

SWR:

import useSWR from 'swr'

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher)
  if (error) return <div>Failed to load</div>
  if (!data) return <div>Loading...</div>
  return <div>Hello {data.name}!</div>
}

Data Client:

import { useResource } from '@data-client/react';

function Profile() {
  const user = useResource(User, { id: 1 });
  if (!user) return <div>Loading...</div>
  return <div>Hello {user.name}!</div>
}

Key Differences

  • SWR focuses on simplicity and ease of use, while Data Client offers more advanced features for complex data management
  • Data Client provides stronger typing and normalization capabilities, which can be beneficial for larger applications
  • SWR has a larger community and more third-party integrations, making it easier to find solutions and extensions

Use Cases

  • SWR: Ideal for smaller to medium-sized projects with straightforward data fetching needs
  • Data Client: Better suited for large-scale applications with complex data relationships and advanced caching requirements

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.

Pros of Apollo Client

  • Widely adopted and battle-tested in production environments
  • Extensive documentation and community support
  • Seamless integration with Apollo Server and other Apollo ecosystem tools

Cons of Apollo Client

  • Larger bundle size, which may impact application performance
  • Steeper learning curve for developers new to GraphQL
  • Can be overkill for simpler applications or those not fully committed to GraphQL

Code Comparison

Apollo Client:

const client = new ApolloClient({
  uri: 'https://api.example.com/graphql',
  cache: new InMemoryCache()
});

const GET_USERS = gql`
  query GetUsers {
    users {
      id
      name
    }
  }
`;

Data Client:

const client = new DataClient({
  baseUrl: 'https://api.example.com',
  dataExpiryLength: 5 * 60 * 1000,
});

const usersEndpoint = new Endpoint({
  urlPrefix: 'users',
  schema: User,
});

Both libraries aim to simplify data fetching and state management in applications, but they take different approaches. Apollo Client is specifically designed for GraphQL, offering a comprehensive solution for GraphQL-based applications. Data Client, on the other hand, is more flexible and can work with various API types, including REST and GraphQL. Data Client focuses on performance and minimal bundle size, making it potentially more suitable for smaller projects or those with mixed API requirements.

The official, opinionated, batteries-included toolset for efficient Redux development

Pros of Redux Toolkit

  • Widely adopted and well-established in the React ecosystem
  • Comprehensive documentation and large community support
  • Includes utilities for common Redux use cases, reducing boilerplate

Cons of Redux Toolkit

  • Can be complex for simple applications
  • Requires more setup and configuration compared to Data Client
  • May lead to excessive re-renders if not optimized properly

Code Comparison

Redux Toolkit:

import { createSlice } from '@reduxjs/toolkit'

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment: state => state + 1,
  },
})

Data Client:

import { Entity } from '@data-client/rest';

class Counter extends Entity {
  id = null;
  value = 0;

  increment() {
    return { ...this, value: this.value + 1 };
  }
}

Key Differences

  • Redux Toolkit focuses on state management, while Data Client is designed for data fetching and caching
  • Data Client provides a more object-oriented approach to data modeling
  • Redux Toolkit requires explicit actions and reducers, whereas Data Client uses method calls on entities

Use Cases

  • Redux Toolkit: Complex state management in large applications
  • Data Client: API-driven applications with a focus on data normalization and caching

Both libraries have their strengths, and the choice depends on the specific needs of your project and team preferences.

18,398

Relay is a JavaScript framework for building data-driven React applications.

Pros of Relay

  • Developed and maintained by Facebook, ensuring robust support and regular updates
  • Tightly integrated with GraphQL, providing optimized data fetching and caching
  • Offers powerful features like automatic query colocation and fragment composition

Cons of Relay

  • Steeper learning curve due to its complex architecture and concepts
  • Requires a specific GraphQL server setup, limiting flexibility with other API types
  • Can be overkill for smaller projects or simpler data requirements

Code Comparison

Relay:

const RepositoryNameFragment = graphql`
  fragment RepositoryName_repository on Repository {
    name
  }
`;

function RepositoryName(props) {
  const data = useFragment(RepositoryNameFragment, props.repository);
  return <h1>{data.name}</h1>;
}

Data Client:

const repository = useResource(RepositoryResource.detail(), { id });

return <h1>{repository.name}</h1>;

Key Differences

  • Relay is specifically designed for GraphQL, while Data Client supports REST and GraphQL
  • Data Client offers a simpler API and easier setup, making it more accessible for beginners
  • Relay provides more advanced features for complex data requirements and large-scale applications
  • Data Client has a smaller bundle size and potentially better performance for simpler use cases

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Reactive Data Client

The scalable way to build applications with dynamic data.

Declarative resouce definitons for REST, GraphQL, Websockets+SSE and more
Performant rendering in React, NextJS, React Native, ExpoGo

Schema driven. Zero updater functions.

CircleCI Coverage Status Percentage of issues still open bundle size npm version PRs Welcome Chat

📖Read The Docs  |  🏁Getting Started
🎮 Demos:   Todo  |  Github Social  |  NextJS SSR  |  Websockets+SSR

Installation

npm install --save @data-client/react @data-client/rest @data-client/test

For more details, see the Installation docs page.

Usage

Simple TypeScript definition

class User extends Entity {
  id = '';
  username = '';
}

class Article extends Entity {
  id = '';
  title = '';
  body = '';
  author = User.fromJS();
  createdAt = Temporal.Instant.fromEpochSeconds(0);

  static schema = {
    author: User,
    createdAt: Temporal.Instant.from,
  };
}

Create collection of API Endpoints

const UserResource = resource({
  path: '/users/:id',
  schema: User,
  optimistic: true,
});

const ArticleResource = resource({
  path: '/articles/:id',
  schema: Article,
  searchParams: {} as { author?: string },
  optimistic: true,
  paginationField: 'cursor',
});

One line data binding

const article = useSuspense(ArticleResource.get, { id });
return (
  <article>
    <h2>
      {article.title} by {article.author.username}
    </h2>
    <p>{article.body}</p>
  </article>
);

Reactive Mutations

const ctrl = useController();
return (
  <>
    <CreateArticleForm
      onSubmit={article =>
        ctrl.fetch(ArticleResource.getList.push, { id }, article)
      }
    />
    <ProfileForm
      onSubmit={user =>
        ctrl.fetch(UserResource.update, { id: article.author.id }, user)
      }
    />
    <button onClick={() => ctrl.fetch(ArticleResource.delete, { id })}>
      Delete
    </button>
  </>
);

Subscriptions

const price = useLive(PriceResource.get, { symbol });
return price.value;

Type-safe Imperative Actions

const ctrl = useController();
ctrl.expireAll(ArticleResource.getList);
ctrl.invalidate(ArticleResource.get, { id });
ctrl.invalidateAll(ArticleResource.getList);
ctrl.setResponse(ArticleResource.get, { id }, articleData);
ctrl.set(Article, { id }, articleData);
ctrl.fetchIfStale(ArticleResource.get, { id });
ctrl.fetch(ArticleResource.update, { id }, articleData);

Programmatic queries

const queryTotalVotes = new schema.Query(
  new schema.Collection([BlogPost]),
  posts => posts.reduce((total, post) => total + post.votes, 0),
);

const totalVotes = useQuery(queryTotalVotes);
const totalVotesForUser = useQuery(queryTotalVotes, { userId });
const groupTodoByUser = new schema.Query(
  TodoResource.getList.schema,
  todos => Object.groupBy(todos, todo => todo.userId),
);
const todosByUser = useQuery(groupTodoByUser);

Powerful Middlewares

class LoggingManager implements Manager {
  middleware: Middleware = controller => next => async action => {
    console.log('before', action, controller.getState());
    await next(action);
    console.log('after', action, controller.getState());
  };

  cleanup() {}
}
class TickerStream implements Manager {
  middleware: Middleware = controller => {
    this.handleMsg = msg => {
      controller.set(Ticker, { id: msg.id }, msg);
    };
    return next => action => next(action);
  };

  init() {
    this.websocket = new WebSocket('wss://ws-feed.myexchange.com');
    this.websocket.onmessage = event => {
      const msg = JSON.parse(event.data);
      this.handleMsg(msg);
    };
  }
  cleanup() {
    this.websocket.close();
  }
}

Integrated data mocking

const fixtures = [
  {
    endpoint: ArticleResource.getList,
    args: [{ maxResults: 10 }] as const,
    response: [
      {
        id: '5',
        title: 'first post',
        body: 'have a merry christmas',
        author: { id: '10', username: 'bob' },
        createdAt: new Date(0).toISOString(),
      },
      {
        id: '532',
        title: 'second post',
        body: 'never again',
        author: { id: '10', username: 'bob' },
        createdAt: new Date(0).toISOString(),
      },
    ],
  },
  {
    endpoint: ArticleResource.update,
    response: ({ id }, body) => ({
      ...body,
      id,
    }),
  },
];

const Story = () => (
  <MockResolver fixtures={options[result]}>
    <ArticleList maxResults={10} />
  </MockResolver>
);

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

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

Features

Examples

  • Todo: GitHub | Sandbox | Edit on CodeSandbox
  • Github: GitHub | Sandbox
  • NextJS: GitHub | Sandbox | Edit on CodeSandbox
  • Websockets: GitHub | Sandbox | Website

API

Reactive Applications

Define Data

Networking definition

Data model
Data Type Mutable Schema Description Queryable
Object ✅ Entity, schema.Entity mixin single unique object ✅
✅ Union(Entity) polymorphic objects (A | B) ✅
🛑 Object statically known keys 🛑
Invalidate(Entity) delete an entity 🛑
List ✅ Collection(Array) growable lists ✅
🛑 Array immutable lists 🛑
✅ All list of all entities of a kind ✅
Map ✅ Collection(Values) growable maps ✅
🛑 Values immutable maps 🛑
any Query(Queryable) memoized custom transforms ✅

NPM DownloadsLast 30 Days