【发布时间】:2021-11-13 05:29:30
【问题描述】:
有点像这里描述的问题 How to compare oldValues and newValues on React Hooks useEffect?
但就我而言,usePrevious 钩子没有帮助。
想象一下具有多个输入、选择等的表单。您可能想查看https://app.uniswap.org/#/swap 以进行类似的可视化。几乎任何更改都会发生一些操作和数据更新,这将导致多次重新渲染,至少 4 次。例如。
我有 2 个输入,每个代表一个令牌。 Base(第一个)和 Quote(第二个)。
这是 Base 的状态
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。
通过在选择菜单中更改token(而不是BTC,我将选择ETH)我将触发几个操作:获取钱包余额,获取价格,然后将通过输入视图更新和模式窗口关闭进行更多的重新渲染。因此,其中至少有 4 个正在发生。我希望能够将base.token 和basePrv 与
const basePrv = usePrevious(base?.token); 但在第二次重新渲染时,base.token 和 basePrv 已经拥有相同的令牌属性,这是一个问题。
我也有输入之间的交换功能,我应该用引号改变基数和像这样用基数改变引号
setBase(prevState => ({
...prevState,
base: quote
}));
setQuote(prevState => ({
...prevState,
quote: base
}));
在这种情况下,没有应触发的其他请求。
现在我有 useEffect 和 token 依赖于它。但是每次更改令牌时都会触发它,如果您要快速单击,这将导致额外的异步调用和请求的“尾部”。这就是为什么我需要比较更改之前的 token 属性以了解我是否应该因为新货币对的形成而发出额外的调用和请求(BTC/USD 变为 ETH/USD )或者我应该忽略它,因为它只是一个“掉期”(BTC/USD 变成 USD/BTC)并且没有必要进行额外的调用并获取。我只需要,嗯,交换它们,而不是更多。
所以在我的故事中,usePrevious 钩子只会返回一次之前的令牌属性,而在第二次和第三次时,它将被多次重新渲染(将获取其他属性)覆盖到新的。所以在useEffect被触发的时候,我没有机会比较之前的token属性和现在的token属性,因为它们会显示相同的。
我对如何解决它有几个想法,但我不确定它是对还是错,因为在我看来,这些决定看起来比声明性更重要。
-
我可以保持一切原样(无论是什么更改,请求都会在任何更改时触发。是交换还是用户更改了一对)。我可以禁用交换按钮,直到所有请求都完成。它将解决请求“尾巴”的问题。但这是一个修补程序,它会起作用,但我不喜欢它,因为它会导致额外的不必要的请求,而且它会很慢而且对 UX 不利。
-
在
setBase或setQuote发生更新之前,我可以使用一个状态来保留前一对。它将允许我使用 useEffect 并将前一对与当前一对进行比较,以了解这对是否已更改,或者只是交换并决定是否进行获取和调用。 -
我可以摆脱
useEffect与base.token和quote.token依赖关系并处理onClick处理程序内部的所有内容。因此,交换功能不会触发useEffect,并且只有当用户单击并选择不同的东西时才会触发调用和提取。但正如我所说,这个选项对我来说似乎有点奇怪。 -
我在这里尝试使用闭包来“记住”令牌的先前状态,但这有点类似于使用当前组件状态。此外,您必须在功能组件主体之外初始化闭包,而且我看不到以这种方式将 init 状态转移到其中的可能性,因此代码变得更加意大利面条。
还有其他想法吗?我肯定错过了一些东西。也许这么多重新渲染是一种反模式,但我不知道如何避免这种情况。
【问题讨论】:
-
为什么不创建一个 prevBase 状态并在可以 setBase 时更新它?
-
这是我在第二种情况下描述的决定。是的,这是可能的,但我选择了第 3 个选项,因为这样我不需要在令牌交换上添加额外的条件或状态或补丁。通过使用
useEffect,它应该使用一些条件来检查和确定我是否应该拨打电话。所以我把所有东西都留在了点击处理程序上。我只是不确定这是否是一个好习惯。 -
我正在回答,因为我无法在评论中给出代码示例。让我知道它是否提供了解决方案。 . .
标签: reactjs react-redux react-hooks use-effect