Pular para o conteúdo principal

useController()

O Controller fornece métodos com tipagem segura para acessar o store e despachar actions para ele.

Por exemplo fetch, invalidate e setResponse

import { useCallback } from 'react';
import { useController } from '@data-client/react';
import { MyResource } from './resources';

function MyComponent({ id }: { id: string }) {
const ctrl = useController();

const handleRefresh = useCallback(
async e => {
await ctrl.fetch(MyResource.get, { id });
},
[ctrl, id],
);

const handleSuspend = useCallback(
async e => {
await ctrl.invalidate(MyResource.get, { id });
},
[ctrl, id],
);

const handleLogout = useCallback(
async e => {
ctrl.resetEntireStore();
},
[ctrl],
);
}

Exemplos​

Envio de formulário​

fetch retorna a resposta desnormalizada, correspondendo ao tipo de retorno de useSuspense(). Isso permite usar métodos de Entity como pk().

import type { FormEvent } from 'react';
import { useNavigate } from 'react-router';
import { useController } from '@data-client/react';
import { PostResource } from './PostResource';

function CreatePost() {
const ctrl = useController();
const navigate = useNavigate();

const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
const post = await ctrl.fetch(
PostResource.getList.push,
new FormData(e.target as HTMLFormElement),
);
post.title;
post.computedField;
navigate(`/post/${post.pk()}`);
};

return <form onSubmit={handleSubmit}>{/* fields */}</form>;
}

Atualização direta de entity​

Use set para atualizações imediatas, sem requisições de rede. Oferece suporte a atualizações funcionais para evitar condições de corrida.

import { useController } from '@data-client/react';
import { Article } from './Article';

function VoteButton({ articleId }: { articleId: string }) {
const ctrl = useController();

return (
<button
onClick={() =>
ctrl.set(Article, { id: articleId }, article => ({
...article,
votes: article.votes + 1,
}))
}
>
Vote
</button>
);
}

Invalidar após uma mutação​

Force um novo fetch dos dados relacionados usando invalidate ou expireAll.

import { useController } from '@data-client/react';
import { UserResource } from './UserResource';

function ClearUserCache({ userId }: { userId: string }) {
const ctrl = useController();

const handleClear = async () => {
// invalidate() causes suspense; expireAll() refetches silently
ctrl.expireAll(UserResource.get);
ctrl.expireAll(UserResource.getList);
};

return <button onClick={handleClear}>Refresh user data</button>;
}
dica

Prefetching​

Use fetchIfStale para fazer prefetch sem buscar novamente dados que ainda estão atualizados.

import { Link } from 'react-router';
import { useController } from '@data-client/react';
import { ArticleResource } from './ArticleResource';

function ArticleLink({ id }: { id: string }) {
const ctrl = useController();

return (
<Link
to={`/article/${id}`}
onMouseEnter={() => ctrl.fetchIfStale(ArticleResource.get, { id })}
>
Read more
</Link>
);
}

Atualizações via websocket​

Preencha o cache com dados externos por meio de set.

import { useEffect } from 'react';
import { useController } from '@data-client/react';
import { EntityMap } from './resources';

function useWebsocket(url: string) {
const ctrl = useController();

useEffect(() => {
const ws = new WebSocket(url);
ws.onmessage = event => {
const { entity, args, data } = JSON.parse(event.data);
ctrl.set(EntityMap[entity], args, data);
};
return () => ws.close();
}, [ctrl, url]);
}
aviso

Em produção, implemente um Manager para streams de dados em vez de effects no nível do componente. Managers lidam com o ciclo de vida da conexão de forma global e funcionam com SSR.

Todo App​

Explore o exemplo todo-app

More Demos