【问题标题】:useCallback with updated state object - React.jsuseCallback 与更新的状态对象 - React.js
【发布时间】:2021-12-02 13:57:56
【问题描述】:

我在单击按钮时进行了POST API 调用。我们有一个大型状态对象,它作为body 发送给POST 调用。此状态对象会根据页面上的不同用户交互不断更新。

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>
  );
}

handleQuickQuoteWithoutDeals 函数被调用时,我正在从对象中删除一个键。但我想立即用更新的对象调用 API。我这里直接删除deal key,但是如果我用不可变的方式来做,下面的API调用考虑的不是更新的对象而是前一个。

我发现的唯一方法是引入一个新状态并在点击时更新它,然后使用useEffect 挂钩来跟踪这个状态,以便在它发生变化时进行 API 调用。使用这种方法,它会以一种奇怪的方式工作,它会在初始加载时不断调用 API 以及其他奇怪的行为。

有没有更简洁的方法来做到这一点?

【问题讨论】:

    标签: javascript reactjs react-hooks use-effect usecallback


    【解决方案1】:

    目前尚不清楚任何子级将如何调用 handleQuickQuote 回调,但如果您需要在回调范围内关闭 quoteDetails 详细信息的“副本”,那么我建议进行以下小型重构以允许此父组件使用原始的createQuote 函数,而孩子们收到一个带有当前quoteDetails 的记忆回调。

    使用 quoteDetails 作为参数:

    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);
      }
    };
    

    记住一个传入quoteDetails 值的“匿名”回调:

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

    创建quoteDetails的浅拷贝,删除属性,调用createQuote

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

    【讨论】:

    • 我真的很喜欢这个答案。如果我以正常的 JS 方式考虑它,我想我把原本简单的事情复杂化了?尽管“尚不清楚任何孩子如何调用 handleQuickQuote 回调”,但我对此评论感到困惑。我将它们作为道具传递并在 onClick 上触发它们。希望这没有错。 PS:我会尽快尝试您的答案并将其标记为已接受。泰。
    • @ThomasSebastian 哦,我的意思更多是“我不知道孩子们是否需要传递任何参数......但根据当前的使用情况,我假设他们只是在引用关闭的情况下调用在回调中结束”。不过我认为我的假设是正确的。
    猜你喜欢
    • 2020-04-27
    • 2021-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多