Estou tendo um comportamento inesperado. Ou seja, coloquei uma condição de salto na consulta e, mesmo quando a condição de salto deveria ser verdadeira, a consulta continua sendo executada. Fiz uma reprodução mínima do bug.
Aplicativo.jsx:
import { useState } from "react";
import "./App.css";
import { Test } from "../test";
import { useApolloClient } from "@apollo/client";
export default function App() {
const [bool, setBool] = useState(false);
const client = useApolloClient();
return (
<main>
<button
onClick={() => {
if (bool) {
client.resetStore();
}
setBool((bool) => {
return !bool;
});
}}
>
Click me
</button>
{bool && <Test bool={bool} />}
</main>
);
}
teste.jsx:
import { gql, useQuery } from "@apollo/client";
const testQuery = gql`
query {
countries {
name
}
}
`;
export const Test = ({ bool }) => {
const { data, loading, error } = useQuery(testQuery, {
skip: !bool,
variables:{holy:"shit"}
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<div>
{data.countries.map((country) => (
<div key={country.name}>{country.name}</div>
))}
</div>
);
};
Estou usando a API de países fornecida pela Apollo GraphQL.
Aqui, quando o botão é clicado pela primeira vez, a consulta é enviada ao servidor que faz sentido. Então, quando ele é clicado novamente (ou seja, tornando bool=false), o cache deve ser limpo e a consulta não deve ser executada, pois está sendo ignorada, mas ela é executada (posso ver que está em execução olhando para a guia de rede). Ao fazer a renderização condicional do teste, pensei que a consulta não seria executada com certeza, pois o componente nem renderizava, mas estava sendo executado novamente, então acho que o problema é que a consulta está em execução entre o momento em que o cache é limpo e o ReactJS atualiza completamente o estado. Acho que não entendo alguns conceitos sobre estados. Como posso evitar que a consulta seja executada quando eu não quero? Agradeço sua ajuda.
Você pode ver aqui por si mesmo relitLink
Emitir
O problema parece ser que o
onClick
manipuladorApp
está fazendo duas coisas:client.resetStore();
quandobool
é verdadebool
atualização de estado para alternar o valor para falsoO que suspeito que esteja acontecendo é que o cliente de consulta é redefinido imediatamente e a atualização de estado do React é apenas enfileirada e processada algum tempo depois pelo React. Enquanto o cliente de consulta é redefinido e
Test
ainda está montado, outra solicitação de consulta é disparada pouco antes do React processar a atualização de estado enfileirada e acionar umaApp
nova renderização do componente, que resultará naTest
desmontagem.Sugestões de soluções
Atrase a
client.restore
chamada por um pequeno atraso para que ela seja efetuada após abool
atualização de estado ter a chance de ser processada e aApp
árvore de componentes renderizada novamente.* Observação: Isso parece funcionar com um atraso de apenas 4 a 5 ms, mas usei um valor maior por precaução. Você pode ajustar isso para atender melhor às suas necessidades.
Use
AbortController
e cancele quaisquer solicitações em andamento quandoTest
o componente for desmontado.Acho que o que está acontecendo é que, quando
bool
se torna falso, o componente Test é desmontado instantaneamente e o hook useQuery não consegue registrar que a consulta deve ser ignorada. Portanto, para ouseQuery
hook, o valor passado para skip ainda é falso. Agora, como o Apollo busca novamente todas as consultas ativas após chamarresetStore()
essa consulta, ela também está sendo buscada novamente.A documentação do ApolloGraphQL afirma que
Então, tecnicamente, a consulta não deveria ser chamada, já que o componente não está montado, então pode ser um bug.
Corrigi o problema não renderizando condicionalmente o componente inteiro, mas apenas a interface do usuário (UI) do componente, e deixando a consulta ser ignorada quando bool for falso.
Aplicativo.jsx:
teste.jsx: