Skip to content

Commit

Permalink
fix: memoize more swap (#2950)
Browse files Browse the repository at this point in the history
* fix: memoize derived swap info

* fix: memoize current block timestamp

* fix: memoize price impact

* fix: memoize debounced value updates

* fix: nits
  • Loading branch information
zzmp authored Jan 18, 2022
1 parent 850a20f commit d54783a
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 48 deletions.
19 changes: 13 additions & 6 deletions src/hooks/useBestTrade.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { InterfaceTrade, TradeState } from 'state/routing/types'
import { useRoutingAPITrade } from 'state/routing/useRoutingAPITrade'

Expand All @@ -24,7 +25,10 @@ export function useBestTrade(
const autoRouterSupported = useAutoRouterSupported()
const isWindowVisible = useIsWindowVisible()

const [debouncedAmount, debouncedOtherCurrency] = useDebounce([amountSpecified, otherCurrency], 200)
const [debouncedAmount, debouncedOtherCurrency] = useDebounce(
useMemo(() => [amountSpecified, otherCurrency], [amountSpecified, otherCurrency]),
200
)

const routingAPITrade = useRoutingAPITrade(
tradeType,
Expand Down Expand Up @@ -56,9 +60,12 @@ export function useBestTrade(
)

// only return gas estimate from api if routing api trade is used
return {
...(useFallback ? bestV3Trade : routingAPITrade),
...(debouncing ? { state: TradeState.SYNCING } : {}),
...(isLoading ? { state: TradeState.LOADING } : {}),
}
return useMemo(
() => ({
...(useFallback ? bestV3Trade : routingAPITrade),
...(debouncing ? { state: TradeState.SYNCING } : {}),
...(isLoading ? { state: TradeState.LOADING } : {}),
}),
[bestV3Trade, debouncing, isLoading, routingAPITrade, useFallback]
)
}
4 changes: 4 additions & 0 deletions src/hooks/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
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/
export default function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
Expand Down
7 changes: 5 additions & 2 deletions src/lib/hooks/useCurrencyBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ export function useTokenBalances(

// get the balance for a single token/account combo
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
return tokenBalances[token.address]
}
Expand All @@ -115,7 +118,7 @@ export function useCurrencyBalances(

const tokenBalances = useTokenBalances(account, tokens)
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(
() =>
Expand Down
5 changes: 4 additions & 1 deletion src/pages/Swap/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ export default function Swap({ history }: RouteComponentProps) {

const fiatValueInput = useUSDCValue(parsedAmounts[Field.INPUT])
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 isValid = !swapInputError
Expand Down
91 changes: 52 additions & 39 deletions src/state/swap/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,55 +136,68 @@ export function useDerivedSwapInfo(): {
(isExactIn ? outputCurrency : inputCurrency) ?? undefined
)

const currencyBalances = {
[Field.INPUT]: relevantTokenBalances[0],
[Field.OUTPUT]: relevantTokenBalances[1],
}
const currencyBalances = useMemo(
() => ({
[Field.INPUT]: relevantTokenBalances[0],
[Field.OUTPUT]: relevantTokenBalances[1],
}),
[relevantTokenBalances]
)

const currencies: { [field in Field]?: Currency | null } = {
[Field.INPUT]: inputCurrency,
[Field.OUTPUT]: outputCurrency,
}
const currencies: { [field in Field]?: Currency | null } = useMemo(
() => ({
[Field.INPUT]: inputCurrency,
[Field.OUTPUT]: outputCurrency,
}),
[inputCurrency, outputCurrency]
)

let inputError: ReactNode | undefined
if (!account) {
inputError = <Trans>Connect Wallet</Trans>
}
const allowedSlippage = useSwapSlippageTolerance(trade.trade ?? undefined)
const inputError = useMemo(() => {
let inputError: ReactNode | undefined

if (!currencies[Field.INPUT] || !currencies[Field.OUTPUT]) {
inputError = inputError ?? <Trans>Select a token</Trans>
}
if (!account) {
inputError = <Trans>Connect Wallet</Trans>
}

if (!parsedAmount) {
inputError = inputError ?? <Trans>Enter an amount</Trans>
}
if (!currencies[Field.INPUT] || !currencies[Field.OUTPUT]) {
inputError = inputError ?? <Trans>Select a token</Trans>
}

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>
if (!parsedAmount) {
inputError = inputError ?? <Trans>Enter an amount</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
const [balanceIn, amountIn] = [currencyBalances[Field.INPUT], trade.trade?.maximumAmountIn(allowedSlippage)]
// compare input balance to max input based on version
const [balanceIn, amountIn] = [currencyBalances[Field.INPUT], trade.trade?.maximumAmountIn(allowedSlippage)]

if (balanceIn && amountIn && balanceIn.lessThan(amountIn)) {
inputError = <Trans>Insufficient {amountIn.currency.symbol} balance</Trans>
}
if (balanceIn && amountIn && balanceIn.lessThan(amountIn)) {
inputError = <Trans>Insufficient {amountIn.currency.symbol} balance</Trans>
}

return {
currencies,
currencyBalances,
parsedAmount,
inputError,
trade,
allowedSlippage,
}
return inputError
}, [account, allowedSlippage, currencies, currencyBalances, parsedAmount, to, trade.trade])

return useMemo(
() => ({
currencies,
currencyBalances,
parsedAmount,
inputError,
trade,
allowedSlippage,
}),
[allowedSlippage, currencies, currencyBalances, inputError, parsedAmount, trade]
)
}

function parseCurrencyFromURLParameter(urlParam: any): string {
Expand Down

0 comments on commit d54783a

Please sign in to comment.