Pular para o conteúdo principal

Data Client para Coding Agents

· 7 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

Coding agents escrevem muito código com Data Client hoje, e escrevem melhor quando têm a documentação e os fluxos de trabalho atuais em vez de adivinhar a partir de versões antigas. Este ciclo de lançamento torna isso mais fácil de configurar para qualquer agent.

Novidades:

  • Plugin do Claude Code - claude plugin install react@data-client instala as skills do seu framework
  • Skills de Vue - Projetos Vue recebem composables e testes de Vue, não hooks de React
  • llms.txt - Qualquer agent pode ler a documentação como markdown, e cada página indica onde procurar

Também disponível:

v0.19: Controller.set() em lote, TypeScript mais rápido

· 28 min para ler
Nathaniel Tucker
Creator of Reactive Data Client
observação

O original em inglês mudou depois desta tradução, então ela pode estar desatualizada.

A v0.19 permite que um Manager escreva um lote inteiro de linhas recebidas por stream em uma única atualização da store, verifica os tipos do código de endpoints cerca de 2x mais rápido e corrige uma rodada de problemas de TypeScript e Vue. Coding agents também ganham um plugin do Claude Code, skills de Vue e llms.txt; veja Data Client para Coding Agents.

Novas APIs:

Desempenho:

Outras melhorias:

  • Corrige a resolução de módulos do TypeScript 7 para os exports do pacote; os imports agora resolvem para os arquivos de declaração (#4019)
  • renderDataHook() executa os efeitos de montagem do provider quando a primeira renderização suspende (#4099)
  • Os valores de Controller.set() são tipados pelo schema, então ctrl.set(new schema.All(Todo), 42) é um erro de TypeScript (#4133)
  • Controller.set() exclui uma entidade com um schema Invalidate sem a gambiarra do lote de uma linha (#4230)
  • process() recebe params tipados em new RestEndpoint(), .extend() e resource().extend(), então um parâmetro de path errado é um erro de TypeScript em vez de undefined em tempo de execução (#4183, #4184)
  • Os retornos de getOptimisticResponse() são tipados pelo schema, então um tipo de campo errado é um erro de TypeScript em vez de um flash de dados incorretos (#4198)
  • useSuspense() e useLive() do Vue mantêm os dados anteriores enquanto novos argumentos carregam, em vez de retornar undefined (#4131)
  • useSuspense() e useLive() do Vue enviam erros de fetch após a mudança de argumentos para onErrorCaptured() em vez de uma rejeição de promise não tratada (#4135)
  • useSuspense(), useDLE() e useFetch() do Vue não buscam mais novamente dados desatualizados a cada atualização da store, então um controller.set() não é sobrescrito (#4134)
  • useSuspense() do Vue mostra dados desatualizados na montagem e busca novamente em segundo plano, como no React, em vez de mostrar o fallback do <Suspense> até a nova busca terminar (#4169)
  • useDLE() e useCache() do Vue mantêm dados invalidIfStale expirados durante atualizações não relacionadas da store, em vez de ficarem travados carregando (#4142)
  • O DataClientPlugin do Vue é instalado em versões do Vue anteriores à 3.5 em vez de lançar app.onUnmount is not a function (#4146)
  • O DataClientPlugin do Vue faz coleta de lixo por padrão, igual ao DataProvider do React, então você não precisa mais passar gcPolicy; como ele decide o que remover (#4148)
  • Os composables do Vue aceitam argumentos getter como () => ({ id: props.id }); eles eram tipados para permiti-los, mas passavam a própria função ao endpoint (#4115)
  • Corrige os erros Cannot find name 'NoInfer' e export type no TypeScript 4.x com skipLibCheck desativado (#4138)
  • Corrige erros de tipo de Entity, Endpoint, Union e RestEndpoint no TypeScript 4.0–4.5 com skipLibCheck desativado (#4140)
  • Corrige erros ',' expected ao importar @data-client/react/redux, @data-client/react/nextjs ou @data-client/test no TypeScript 4.0–4.4 (#4232)
  • Corrige act e renderHook de @data-client/test tipados como any no TypeScript 4.0–4.4 (#4251)
  • Classes Entity podem ser usadas onde um EntityInterface é esperado (#4149); prepare as sobrescritas de pk() para um lançamento futuro
  • useCache() e useDLE() retornam undefined para uma entidade excluída cuja nova busca falhou, em vez de um Symbol truthy que passava por verificações if (!data); remova quaisquer gambiarras (#4150)
  • useFetch() do Vue impede que seus dados sejam coletados pelo garbage collector enquanto está montado, como o useSuspense(), então um gcPolicy configurado não remove mais dados pré-carregados que componentes leem depois (#4152)
  • Apps com o Redux DevTools aberto não travam mais em desenvolvimento com stores grandes ou atualizações frequentes; cada atualização serializa 40-60x mais rápido (#4163)
  • resource().extend() com um objeto de sobrescritas de endpoints mantém em seu tipo os endpoints adicionados antes com .extend('name', options), então usá-los não é mais um erro de TypeScript (#4184)
  • RestEndpoint.push, unshift e remove aceitam os campos da Entity como body quando um Query ou Lazy envolve a Collection, em vez de apenas FormData (#4226)
  • useFetch() do Vue é tipado como o Ref somente leitura que retorna, então promise.resolved (sempre undefined) agora é um erro de TypeScript; leia promise.value.resolved em vez disso (#4114)
  • Uma subclasse de Controller passada ao DataProvider ou ao DataClientPlugin não precisa mais de um cast para passar na verificação de tipos (#4228)
  • A store de prepareStore() pode ser passada ao <Provider> do react-redux sem cast, e tem dispatch() em seu tipo (#4238)
  • resource().create aceita FormData sem cast, como update, partialUpdate e getList.push (#4235)
  • RestEndpoint.push, unshift e remove enviam um body em array como JSON, então criar ou remover vários itens de uma vez não envia mais "[object Object]" ao seu servidor; resource().create também aceita um array (#4262)
  • O createDataClient() do Vue está descontinuado, já que é interno ao DataClientPlugin; instale o plugin com app.use(DataClientPlugin, options) em vez de chamá-lo diretamente (#4193)
  • O waitForNextUpdate() do renderDataCompose() do Vue está descontinuado, já que desiste silenciosamente após 1 segundo e deixa um teste passar enquanto ainda está suspenso; use await result em vez disso, ou await allSettled() após uma mudança, que agora também espera as buscas iniciadas por uma mudança de prop (testes unitários de composables, #4221)

Mudanças incompatíveis:

Prepare-se para lançamentos futuros:

v0.18: Scalar, downloads de arquivo tipados, Collections conscientes de filtros

· 12 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

A v0.18 foca em uma modelagem de dados mais rica para valores que variam conforme o contexto da requisição, downloads tipados mais simples e uma correspondência de collections que reflete melhor os filtros reais das APIs.

Novos recursos:

Outras melhorias:

Fixtures
▶api/Company
import { Collection, Entity, RestEndpoint, Scalar } from '@data-client/rest';

export class Company extends Entity {
  id = '';
  name = '';
  price = 0;
  pct_equity = 0;
  shares = 0;
}

const PortfolioScalar = new Scalar({
  lens: args => args[0]?.portfolio,
  key: 'portfolio',
  entity: Company,
});
Company.schema = {
  pct_equity: PortfolioScalar,
  shares: PortfolioScalar,
};

export const getCompanies = new RestEndpoint({
  path: '/companies',
  searchParams: {} as { portfolio: string },
  // `portfolio` is a lens, not a filter — the returned Company list is the same
  // regardless of lens. Dropping it from `argsKey` collapses every portfolio to
  // one Collection pk, so `Collection.queryKey()` finds the list on every
  // switch and `useSuspense` reuses it without refetching.
  schema: new Collection([Company], { argsKey: () => ({}) }),
});

export const getPortfolioColumns = new RestEndpoint({
  path: '/companies/columns',
  searchParams: {} as { portfolio: string },
  schema: new Collection([PortfolioScalar], {
    argsKey: ({ portfolio }: { portfolio: string }) => ({ portfolio }),
  }),
});
▶CompanyGrid
▶PortfolioGrid
Resultado
Store▶

O exemplo mostra as mesmas entidades Company renderizadas através de diferentes lentes de portfólio. Os campos estáveis da Entity são reutilizados, enquanto os valores dependentes de lente são selecionados de células Scalar separadas.

Mudanças incompatíveis:

Usa um agente de IA? Instale a skill de migração — ela executa o codemod, registra argsKey para schemas dependentes de args e trata os casos que o codemod não consegue (campos de classe, atribuição dinâmica de métodos, blocos <script> de SFC, helpers personalizados):

npx skills add reactive/data-client --skill data-client-v0.18-migration

Caso contrário, execute o codemod diretamente — ele cobre os casos comuns:

npx jscodeshift -t https://dataclient.io/codemods/v0.18.js --extensions=ts,tsx,js,jsx src/

v0.16: Busca em paralelo, Collection.move, Lazy

· 13 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

Novos recursos:

Outras melhorias:

Collection.move facilita mover entidades entre Collections com uma única operação:

import { useController } from '@data-client/react';
import { TaskResource, type Task } from './TaskResource';

export default function TaskCard({ task }: { task: Task }) {
  const handleMove = () => ctrl.fetch(
    TaskResource.getList.move,
    { id: task.id },
    { id: task.id, status: task.status === 'backlog' ? 'in-progress' : 'backlog' },
  );
  const ctrl = useController();
  return (
    <div className="listItem">
      <span style={{ flex: 1 }}>{task.title}</span>
      <button onClick={handleMove}>
        {task.status === 'backlog' ? '\u25bc' : '\u25b2'}
      </button>
    </div>
  );
}
Resultado

Mudanças incompatíveis:

Atualize com um codemod automatizado para todas as mudanças incompatíveis:

npx jscodeshift -t https://dataclient.io/codemods/v0.16.js --extensions=ts,tsx,js,jsx src/

v0.15: Vue 3, Collection.remove, atualização do useDebounce

· 10 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

Novas plataformas:

  • Vue 3 com composables completos: useSuspense, useCache, useDLE, useController, useQuery

Novos recursos:

Desempenho:

Mudanças incompatíveis:

Atualize com um codemod automatizado para as mudanças incompatíveis mais comuns:

npx jscodeshift -t https://dataclient.io/codemods/v0.15.js --extensions=ts,tsx,js,jsx src/

v0.14: APIs de Manager simplificadas, desempenho e GC

· 13 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

Managers:

As APIs de Manager foram simplificadas — formatos de action mais planos reduzem a complexidade do código e melhoram o desempenho ao minimizar entradas distintas de cache inline, enquanto APIs de configuração mais simples tornam a personalização mais agradável.

Desempenho:

Schema/modelagem de dados:

Testes:

Coleta de lixo:

  • GCPolicy - coleta de lixo automática de dados desatualizados

Mudanças incompatíveis:

v0.13: NextJS App Router, Expo, React 19, Redux

· 9 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

Plataformas:

Testes:

Pacotes movidos para dentro de @data-client/react:

  • Redux
  • Hooks

Outras melhorias

Mudanças incompatíveis:

observação

A versão 0.12 foi pulada devido a um problema na publicação.

v0.11 Queries, Queryable e useQuery

· 12 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

Além dos benefícios de desempenho e integridade de dados de normalizar o estado, ganhamos a vantagem adicional de poder acessar e consultar a store diretamente com segurança.

Nesta versão, ajustamos e simplificamos essa funcionalidade unificando tudo em torno do conceito de Schemas Queryable. Eles incluem Entity, All, Collection, Query e Union

O maior impacto dessa mudança é a introdução de um novo hook, useQuery(), que permite consultas diretas à store usando os Schemas Queryable.

class User extends Entity {
username = '';
id = '';
groupId = '';
pk() {
return this.id;
}
static index = ['username' as const];
}

const bob = useQuery(User, { username: 'bob' });
const bob = useQuery(User, { id: '5' });

De forma semelhante, podemos consultar Queryables com o controller e o snapshot usando controller.get

const bob = snapshot.get(User, { username: 'bob' });

Além disso, investimos em mais melhorias de desempenho, resultando em um ganho de cerca de 2x na maioria das operações e em Queries 16x mais rápidas.

Guia de migração

Mudanças incompatíveis:

Outros destaques:

v0.10: Tratamento consistente de null, utilitários de URL

· 4 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

Esta versão foca em consistência e extensibilidade. O tratamento de null agora é uniforme em todos os tipos de schema, tornando as transformações de dados mais previsíveis. Novos utilitários de URL permitem construção personalizada de URLs e codificação de parâmetros de busca.

class MyEndpoint<O extends RestGenerics = any> extends RestEndpoint<O> {
searchToString(searchParams) {
// Use qs library for complex nested object encoding
return qs.stringify(searchParams);
}
}
Guia de migração

Mudanças incompatíveis:

Outras melhorias:

v0.9: DevTools, Resource.extend e limpeza de legado

· 8 min para ler
Nathaniel Tucker
Creator of Reactive Data Client

Esta versão foca na experiência do desenvolvedor, com um botão de devtools que aparece em modo de desenvolvimento, um histórico do DevTools melhor e novos métodos do controller como controller.expireAll() e controller.fetchIfStale().

Resource.extend() oferece três maneiras poderosas de personalizar resources - adicionar novos endpoints, sobrescrever os existentes ou derivar a partir dos endpoints de base.

const UserResource = createResource({
path: '/users/:id',
schema: User,
}).extend('current', {
path: '/users/current',
});
Guia de migração

Mudanças incompatíveis: