当前位置: 首页 > 知识库问答 >
问题:

如何在效果上比较旧值和新值?多次重新渲染

朱高超
2023-03-14

有点像这里描述的问题如何比较反应挂钩使用效果的旧值和新值?

但是在我的例子中,useprovalhook没有帮助。

想象一下这个表单有几个输入、选择等等。你可能想看看https://app.uniswap.org/#/swap 进行类似的可视化。几乎任何更改都会发生多个操作和数据更新,这将导致多次重新渲染,至少4次。例如

我有两个输入,每个代表一个标记。基础(第一个)和报价(第二个)。

这是基地的状态

const [base, setBase] = useState({
    balance: undefined,
    price: undefined,
    value: initState?.base?.value,
    token: initState?.base?.token,
    tokenId: initState?.base?.tokenId,
});

并引用

const [quote, setQuote] = useState({
    balance: undefined,
    price: undefined,
    value: initState?.quote?.value,
    token: initState?.quote?.token,
    tokenId: initState?.quote?.tokenId,
});

他们会形成一对,比如BTC/USD。

通过更改选择菜单中的令牌(而不是BTC,我将选择ETH),我将触发多个操作:获取钱包余额、获取价格,并且将有更多的重新提交程序,输入视图更新和模式窗口关闭。因此,目前至少有4起此类事件正在发生。我希望能够比较base。令牌basePrvconst basePrv=useprovian(base?.token) 但在第二次重新渲染基。令牌basePrv将具有相同的令牌属性,这是一个问题。

我也有输入之间的交换功能,我应该用quote和quote来改变base,就像这样

setBase(prevState => ({
    ...prevState,
    base: quote
}));

setQuote(prevState => ({
    ...prevState,
    quote: base
}));

在这种情况下,不应触发其他请求。

现在,我对它有use效应令牌依赖关系。但是每次当令牌要更改时,它都会被触发,这将导致额外的异步调用和请求的“尾部”,如果你要快速单击的话。这就是为什么我需要比较更改之前的令牌属性,以了解我是否应该因为新对的形成(BTC/USD变成ETH/USD)而进行额外的调用和请求,或者我应该忽略它,因为它只是一个"交换”(BTC/USD变成USD/BTC),不需要进行额外的调用和提取。我只是不得不,嗯,交换它们,而不是更多。

因此,在我的故事中,usePrevioushook将只返回前一个令牌属性一次,在第二次和第三次时,它将被多个重新呈现(将获取其他属性)覆盖到新的令牌属性。因此,在触发useffect时,我将没有机会比较上一个令牌属性和当前令牌属性,因为它们将显示相同的属性。

关于如何解决这个问题,我有一些想法,但我不确定这是对还是错,因为在我看来,这些决定看起来更具必要性,而不是陈述性。

>

  • 我可以让一切保持原样(请求总是在任何更改时触发,无论更改是什么。是交换还是用户更改了一对)。我可以禁用交换按钮,直到所有请求都完成。它将解决请求“tail”的问题。但这是一种热修复,这将是可行的,但我不喜欢它,因为它会导致额外的不必要的请求,它将是缓慢的,不利于用户体验。

    在由setBasesetQuote更新之前,我可以使用一个状态来保持前一对。它将允许我使用use效应,并将前一对与当前一对进行比较,以了解该对是否已更改,或者只是交换,并决定我是否应该进行读取和调用。

    我可以用base摆脱useffect。令牌报价。标记依赖项,并处理onClick处理程序中的所有内容。因此,交换功能不会触发useffect,只有当用户单击并选择不同的内容时,才会触发调用和获取。但正如我所说,这个选择对我来说似乎有点奇怪。

    我试图在这里使用闭包来“记住”令牌的前一个状态,但它有点类似于使用当前组件状态。另外,您必须在功能组件主体之外初始化闭包,我看不出有可能以这种方式将init状态转移到闭包中,因此代码变得更加杂乱无章。

    伙计们还有其他想法吗?我肯定错过了什么。也许很多重新渲染是反模式,但我不确定如何避免。


  • 共有1个答案

    孔海超
    2023-03-14

    您的问题可能有多种解决方案。我建议选择一个更容易理解的。

    您可以修改usePre以往钩子以在多个呈现中存活。

    提示:使用JSON. stringify比较,如果您认为值将是一个复杂的对象,并且可能会更改引用,即使是相同的实际值。

    function usePrevious(value) {
      const prevRef = useRef();
      const curRef = useRef();
    
      if (value !== curRef.current){
      // or, use
      // if ( JSON.stringify(value) !== JSON.stringify(curRef.current)){
        prevRef.current = curRef.current;
        curRef.current = value;
      }
      
      return prevRef.current;
    }
    

    因为您使用令牌(字符串)作为use效应的依赖数组,并且您不介意它们的顺序(交换不应该改变任何东西),所以对依赖数组进行排序,如

    useEffect(
      () => {
        // do some effect
      },
      [base.token, quote.token].sort()
    )
    

    在存储API响应数据的同时,还存储与该数据关联的令牌(请求的一部分)。现在,您将有两套代币。

    1. 当前选择的代币

    您可以选择仅在当前获取的令牌不能满足您的需要时获取。您还可以扩展此功能,存储以前的API请求/响应,并尽可能从中选择结果。

    在所有这些中,第三似乎是个不错的选择

    我会选择第二个,因为简单和极简主义。然而,这仍然取决于你在最后发现什么更容易。

     类似资料:
    • 我有一个组件,它需要获取数据,将其设置为state,然后将其传递给子级。一些数据还需要在上下文中设置。我的问题是,使用useEffect,一旦调用API,它将为我需要执行的每个setvalue()函数重新呈现。我已经尝试传递useffect一个空的[]数组,由于状态正在改变,仍然得到相同数量的重新渲染。此时数组包含集合。。。用于防止eslint抛出警告的函数。 有没有更好的方法来避免如此多的重新渲

    • 问题内容: 我的目的是观察范围内的模型,并找出旧值和新值之间的差异。 但是,我发现以下代码中的旧值和新值都相同。 输出: 它们为什么相同,如果是故意的,为什么? 这是代码,http://plnkr.co/edit/rfMCF4x6CmVVT957DPSS?p=preview 问题答案: 您可以改用,这似乎可行。如果您还想监视对象上的所有属性(如您所做的那样),则需要将第三个参数添加到监视中。这建立

    • 在下面的代码中,我单击Submit按钮。在backing\u home中,通过ajax调用将布尔值更改为true。 如果我删除渲染的,我会正确地看到更新的输出。但是对于下面的代码,它是。我认为它没有呈现新值 可能是什么原因?

    • 我在树状图中有数据,我使用ObservableList来渲染地图数据。我需要直接在TableView上编辑字符串值。问题是,如何更改TreeMap上的真实数据,即如何从数据列表中获取旧的和新的str值以将其放入map键中。 getOldValue方法不起作用。我用这个方法得到的只是新值。

    • 问题内容: 我有一个名为表,其中有一个名为列,并充满了相同的数字的,等等。 我生成了一个列表,其中包含新的商品编号,它将替换旧的商品编号: 我有一个查询,希望可以解决该查询,但是以某种方式它什么也没做。 (当然,我已将其他值嵌套到查询中) 我如何在这样的列中获取将旧值替换为新值的查询? 问题答案: 您只是在选择新替换的值,而不对它们进行任何操作…在使用replace时,这是一个很好的主意,请始终先

    • 我试图将页面中显示的交易编号与用户单击“无交易”链接后下一页中显示的交易编号进行比较。 我尝试了以下方法: 当我运行此命令时,会出现以下错误: 线程“main”组织中出现异常。openqa。硒。StaleElement引用异常:stale元素引用:元素未附加到页面文档(会话信息:chrome=59.0.3071.115)(驱动程序信息:chromedriver=2.29.461591(62ebf0