Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

142
Visualizações
Ignore previous callback result if state has changed in the meantime

I have page displaying a list of countries provided by an external library. When I click on a country, it shows me all cities in it.
Each country object has a method to get the list of cities in it, provided by the library.
I have a CountryComponent like this

import { City, Country } from "an-external-library";

export const CountryComponent: FC<Props> = ({ country: Country }) => {
  const [cities, setCities] = useState<City[]>([]);

  useEffect(() => {
    country
      .getCities()
      .then(setCities)
      .catch(console.error);
  }, [country]);

// ...
}

I want to get cities every time the component mounts and also if the country changes.
The problem is that if I keep changing the country quickly, it will call getCities() every time I click on a country on the list. Since there's no way of knowing in which order the responses to those calls will arrive, in the end cities will be the response that arrived last, whatever it is.
This means I may end up with country: France; cities: New York, Los Angeles, etc...


Solutions I've tried

  • Unmounting CountryComponent and mounting again if country changes.

In the parent component, I have

const handleChangeCountry = (c: Country) => {
  setCountry(undefined);
  setTimeout(() => setCountry(c), 10);
}

render (
  <>
    <CountryList onCountryClick={handleChangeCountry}/>
    {country ?
      <CountryComponent country={country}/>
    :
      <Spinner />
    })
  </>
)

This a solution so ugly that just writing this gives me the creeps.
But it worked. Just that I couldn't get the UI to look clean when the CountryComponent disappeared for 10 ms and appeared again; and want a better solution.


Solutions I haven't tried

As suggested by @chimera, debouncing could be a solution.
While searching for solutions before posting, I found this answer, but didn't try it because I believe that it would cause the list of cities to take a while to respond to clicks on countries, and that's not ideal either.


Ideally, I would like to ignore all callbacks from getCities() except the last, but I don't know how I'd achieve this.

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

This is a typical issue: you get unordered asynchronous responses, potentially overwriting the most recent (and the only relevant) state.

A very easy solution is to use react-use's useAsync hook, which includes several useful mechanisms for this typical issue, the one interesting here being that it discards the responses of every previous requests, keeping only the response to the most recent request.

React hook that resolves an async function or a function that returns a promise;

import { useAsync } from "react-use";

const CountryComponent = ({ country: Country }) => {
  // With react-use's useAsync,
  // no need for separate state and useEffect
  const cities = useAsync(
    () => country.getCities(),
    [country]
  ).value; // returned object { loading: boolean, value: T, error }
  
  // ...
}
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda