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

139
Visualizações
useCallback with updated state object - React.js

I have a POST API call that I make on a button click. We have one large state object that gets sent as body for a POST call. This state object keeps getting updated based on different user interactions on the page.

function QuotePreview(props) {
  const [quoteDetails, setQuoteDetails] = useState({});
  const [loadingCreateQuote, setLoadingCreateQuote] = useState(false);

  useEffect(() => {
    if(apiResponse?.content?.quotePreview?.quoteDetails) {
      setQuoteDetails(apiResponse?.content?.quotePreview?.quoteDetails);
    }
  }, [apiResponse]);

  const onGridUpdate = (data) => {
    let subTotal = data.reduce((subTotal, {extendedPrice}) => subTotal + extendedPrice, 0);
    subTotal = Math.round((subTotal + Number.EPSILON) * 100) / 100

    setQuoteDetails((previousQuoteDetails) => ({
      ...previousQuoteDetails,
      subTotal: subTotal,
      Currency: currencySymbol,
      items: data,
    }));
  };

  const createQuote = async () => {
    try {
      setLoadingCreateQuote(true);
      const result = await usPost(componentProp.quickQuoteEndpoint, quoteDetails);
      if (result.data?.content) {
        /** TODO: next steps with quoteId & confirmationId */
        console.log(result.data.content);
      }
      return result.data;
    } catch( error ) {
      return error;
    } finally {
      setLoadingCreateQuote(false);
    }
  };

  const handleQuickQuote = useCallback(createQuote, [quoteDetails, loadingCreateQuote]);

  const handleQuickQuoteWithoutDeals = (e) => {
    e.preventDefault();
    // remove deal if present
    if (quoteDetails.hasOwnProperty("deal")) {
      delete quoteDetails.deal;
    }
    handleQuickQuote();
  }

  const generalInfoChange = (generalInformation) =>{
    setQuoteDetails((previousQuoteDetails) => (
      {
        ...previousQuoteDetails,
        tier: generalInformation.tier,
      }
    ));
  }

  const endUserInfoChange = (endUserlInformation) =>{
    setQuoteDetails((previousQuoteDetails) => (
      {
        ...previousQuoteDetails,
        endUser: endUserlInformation,
      }
    ));
  }

  return (
    <div className="cmp-quote-preview">
      {/* child components [handleQuickQuote will be passed down] */}
    </div>
  );
}

when the handleQuickQuoteWithoutDeals function gets called, I am deleting a key from the object. But I would like to immediately call the API with the updated object. I am deleting the deal key directly here, but if I do it in an immutable way, the following API call is not considering the updated object but the previous one.

The only way I found around this was to introduce a new state and update it on click and then make use of the useEffect hook to track this state to make the API call when it changes. With this approach, it works in a weird way where it keeps calling the API on initial load as well and other weird behavior.

Is there a cleaner way to do this?

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

0

It's not clear how any children would call the handleQuickQuote callback, but if you are needing to close over in callback scope a "copy" of the quoteDetails details then I suggest the following small refactor to allow this parent component to use the raw createQuote function while children receive a memoized callback with the current quoteDetails enclosed.

Consume quoteDetails as an argument:

const createQuote = async (quoteDetails) => {
  try {
    setLoadingCreateQuote(true);
    const result = await usPost(componentProp.quickQuoteEndpoint, quoteDetails);
    if (result.data?.content) {
      /** TODO: next steps with quoteId & confirmationId */
      console.log(result.data.content);
    }
    return result.data;
  } catch( error ) {
    return error;
  } finally {
    setLoadingCreateQuote(false);
  }
};

Memoize an "anonymous" callback that passes in the quoteDetails value:

const handleQuickQuote = useCallback(
  () => createQuote(quoteDetails),
  [quoteDetails]
);

Create a shallow copy of quoteDetails, delete the property, and call createQuote:

const handleQuickQuoteWithoutDeals = (e) => {
  e.preventDefault();
  const quoteDetailsCopy = { ...quoteDetails };

  // remove deal if present
  if (quoteDetailsCopy.hasOwnProperty("deal")) {
    delete quoteDetailsCopy.deal;
  }
  createQuote(quoteDetailsCopy);
}
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