Commit d54783a3 authored by Zach Pomerantz's avatar Zach Pomerantz Committed by GitHub

fix: memoize more swap (#2950)

* fix: memoize derived swap info

* fix: memoize current block timestamp

* fix: memoize price impact

* fix: memoize debounced value updates

* fix: nits
parent 850a20f6
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { InterfaceTrade, TradeState } from 'state/routing/types' import { InterfaceTrade, TradeState } from 'state/routing/types'
import { useRoutingAPITrade } from 'state/routing/useRoutingAPITrade' import { useRoutingAPITrade } from 'state/routing/useRoutingAPITrade'
...@@ -24,7 +25,10 @@ export function useBestTrade( ...@@ -24,7 +25,10 @@ export function useBestTrade(
const autoRouterSupported = useAutoRouterSupported() const autoRouterSupported = useAutoRouterSupported()
const isWindowVisible = useIsWindowVisible() const isWindowVisible = useIsWindowVisible()
const [debouncedAmount, debouncedOtherCurrency] = useDebounce([amountSpecified, otherCurrency], 200) const [debouncedAmount, debouncedOtherCurrency] = useDebounce(
useMemo(() => [amountSpecified, otherCurrency], [amountSpecified, otherCurrency]),
200
)
const routingAPITrade = useRoutingAPITrade( const routingAPITrade = useRoutingAPITrade(
tradeType, tradeType,
...@@ -56,9 +60,12 @@ export function useBestTrade( ...@@ -56,9 +60,12 @@ export function useBestTrade(
) )
// only return gas estimate from api if routing api trade is used // only return gas estimate from api if routing api trade is used
return { return useMemo(
...(useFallback ? bestV3Trade : routingAPITrade), () => ({
...(debouncing ? { state: TradeState.SYNCING } : {}), ...(useFallback ? bestV3Trade : routingAPITrade),
...(isLoading ? { state: TradeState.LOADING } : {}), ...(debouncing ? { state: TradeState.SYNCING } : {}),
} ...(isLoading ? { state: TradeState.LOADING } : {}),
}),
[bestV3Trade, debouncing, isLoading, routingAPITrade, useFallback]
)
} }
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
/**
* Debounces updates to a value.
* Non-primitives *must* wrap the value in useMemo, or the value will be updated due to referential inequality.
*/
// modified from https://usehooks.com/useDebounce/ // modified from https://usehooks.com/useDebounce/
export default function useDebounce<T>(value: T, delay: number): T { export default function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value) const [debouncedValue, setDebouncedValue] = useState<T>(value)
......
...@@ -99,7 +99,10 @@ export function useTokenBalances( ...@@ -99,7 +99,10 @@ export function useTokenBalances(
// get the balance for a single token/account combo // get the balance for a single token/account combo
export function useTokenBalance(account?: string, token?: Token): CurrencyAmount<Token> | undefined { export function useTokenBalance(account?: string, token?: Token): CurrencyAmount<Token> | undefined {
const tokenBalances = useTokenBalances(account, [token]) const tokenBalances = useTokenBalances(
account,
useMemo(() => [token], [token])
)
if (!token) return undefined if (!token) return undefined
return tokenBalances[token.address] return tokenBalances[token.address]
} }
...@@ -115,7 +118,7 @@ export function useCurrencyBalances( ...@@ -115,7 +118,7 @@ export function useCurrencyBalances(
const tokenBalances = useTokenBalances(account, tokens) const tokenBalances = useTokenBalances(account, tokens)
const containsETH: boolean = useMemo(() => currencies?.some((currency) => currency?.isNative) ?? false, [currencies]) const containsETH: boolean = useMemo(() => currencies?.some((currency) => currency?.isNative) ?? false, [currencies])
const ethBalance = useNativeCurrencyBalances(containsETH ? [account] : []) const ethBalance = useNativeCurrencyBalances(useMemo(() => (containsETH ? [account] : []), [containsETH, account]))
return useMemo( return useMemo(
() => () =>
......
...@@ -137,7 +137,10 @@ export default function Swap({ history }: RouteComponentProps) { ...@@ -137,7 +137,10 @@ export default function Swap({ history }: RouteComponentProps) {
const fiatValueInput = useUSDCValue(parsedAmounts[Field.INPUT]) const fiatValueInput = useUSDCValue(parsedAmounts[Field.INPUT])
const fiatValueOutput = useUSDCValue(parsedAmounts[Field.OUTPUT]) const fiatValueOutput = useUSDCValue(parsedAmounts[Field.OUTPUT])
const priceImpact = routeIsSyncing ? undefined : computeFiatValuePriceImpact(fiatValueInput, fiatValueOutput) const priceImpact = useMemo(
() => (routeIsSyncing ? undefined : computeFiatValuePriceImpact(fiatValueInput, fiatValueOutput)),
[fiatValueInput, fiatValueOutput, routeIsSyncing]
)
const { onSwitchTokens, onCurrencySelection, onUserInput, onChangeRecipient } = useSwapActionHandlers() const { onSwitchTokens, onCurrencySelection, onUserInput, onChangeRecipient } = useSwapActionHandlers()
const isValid = !swapInputError const isValid = !swapInputError
......
...@@ -136,55 +136,68 @@ export function useDerivedSwapInfo(): { ...@@ -136,55 +136,68 @@ export function useDerivedSwapInfo(): {
(isExactIn ? outputCurrency : inputCurrency) ?? undefined (isExactIn ? outputCurrency : inputCurrency) ?? undefined
) )
const currencyBalances = { const currencyBalances = useMemo(
[Field.INPUT]: relevantTokenBalances[0], () => ({
[Field.OUTPUT]: relevantTokenBalances[1], [Field.INPUT]: relevantTokenBalances[0],
} [Field.OUTPUT]: relevantTokenBalances[1],
}),
[relevantTokenBalances]
)
const currencies: { [field in Field]?: Currency | null } = { const currencies: { [field in Field]?: Currency | null } = useMemo(
[Field.INPUT]: inputCurrency, () => ({
[Field.OUTPUT]: outputCurrency, [Field.INPUT]: inputCurrency,
} [Field.OUTPUT]: outputCurrency,
}),
[inputCurrency, outputCurrency]
)
let inputError: ReactNode | undefined const allowedSlippage = useSwapSlippageTolerance(trade.trade ?? undefined)
if (!account) { const inputError = useMemo(() => {
inputError = <Trans>Connect Wallet</Trans> let inputError: ReactNode | undefined
}
if (!currencies[Field.INPUT] || !currencies[Field.OUTPUT]) { if (!account) {
inputError = inputError ?? <Trans>Select a token</Trans> inputError = <Trans>Connect Wallet</Trans>
} }
if (!parsedAmount) { if (!currencies[Field.INPUT] || !currencies[Field.OUTPUT]) {
inputError = inputError ?? <Trans>Enter an amount</Trans> inputError = inputError ?? <Trans>Select a token</Trans>
} }
const formattedTo = isAddress(to) if (!parsedAmount) {
if (!to || !formattedTo) { inputError = inputError ?? <Trans>Enter an amount</Trans>
inputError = inputError ?? <Trans>Enter a recipient</Trans>
} else {
if (BAD_RECIPIENT_ADDRESSES[formattedTo]) {
inputError = inputError ?? <Trans>Invalid recipient</Trans>
} }
}
const allowedSlippage = useSwapSlippageTolerance(trade.trade ?? undefined) const formattedTo = isAddress(to)
if (!to || !formattedTo) {
inputError = inputError ?? <Trans>Enter a recipient</Trans>
} else {
if (BAD_RECIPIENT_ADDRESSES[formattedTo]) {
inputError = inputError ?? <Trans>Invalid recipient</Trans>
}
}
// compare input balance to max input based on version // compare input balance to max input based on version
const [balanceIn, amountIn] = [currencyBalances[Field.INPUT], trade.trade?.maximumAmountIn(allowedSlippage)] const [balanceIn, amountIn] = [currencyBalances[Field.INPUT], trade.trade?.maximumAmountIn(allowedSlippage)]
if (balanceIn && amountIn && balanceIn.lessThan(amountIn)) { if (balanceIn && amountIn && balanceIn.lessThan(amountIn)) {
inputError = <Trans>Insufficient {amountIn.currency.symbol} balance</Trans> inputError = <Trans>Insufficient {amountIn.currency.symbol} balance</Trans>
} }
return { return inputError
currencies, }, [account, allowedSlippage, currencies, currencyBalances, parsedAmount, to, trade.trade])
currencyBalances,
parsedAmount, return useMemo(
inputError, () => ({
trade, currencies,
allowedSlippage, currencyBalances,
} parsedAmount,
inputError,
trade,
allowedSlippage,
}),
[allowedSlippage, currencies, currencyBalances, inputError, parsedAmount, trade]
)
} }
function parseCurrencyFromURLParameter(urlParam: any): string { function parseCurrencyFromURLParameter(urlParam: any): string {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment