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

fix: trade UI latency (#3563)

* fix: do not delay trade update

* fix: do not delay initial input
parent 64e8c3ce
import styled, { css } from 'lib/theme' import styled, { css } from 'lib/theme'
import { forwardRef, HTMLProps, useCallback, useEffect, useState } from 'react' import { forwardRef, HTMLProps, useCallback } from 'react'
const Input = styled.input` const Input = styled.input`
-webkit-appearance: textfield; -webkit-appearance: textfield;
...@@ -76,46 +76,23 @@ interface EnforcedNumericInputProps extends NumericInputProps { ...@@ -76,46 +76,23 @@ interface EnforcedNumericInputProps extends NumericInputProps {
enforcer: (nextUserInput: string) => string | null enforcer: (nextUserInput: string) => string | null
} }
function isNumericallyEqual(a: string, b: string) {
const [aInteger, aDecimal] = toParts(a)
const [bInteger, bDecimal] = toParts(b)
return aInteger === bInteger && aDecimal === bDecimal
function toParts(num: string) {
let [integer, decimal] = num.split('.')
integer = integer?.match(/([1-9]\d*)/)?.[1] || ''
decimal = decimal?.match(/(\d*[1-9])/)?.[1] || ''
return [integer, decimal]
}
}
const NumericInput = forwardRef<HTMLInputElement, EnforcedNumericInputProps>(function NumericInput( const NumericInput = forwardRef<HTMLInputElement, EnforcedNumericInputProps>(function NumericInput(
{ value, onChange, enforcer, pattern, ...props }: EnforcedNumericInputProps, { value, onChange, enforcer, pattern, ...props }: EnforcedNumericInputProps,
ref ref
) { ) {
const [state, setState] = useState(value ?? '')
useEffect(() => {
if (!isNumericallyEqual(state, value)) {
setState(value ?? '')
}
}, [value, state, setState])
const validateChange = useCallback( const validateChange = useCallback(
(event) => { (event) => {
const nextInput = enforcer(event.target.value.replace(/,/g, '.')) const nextInput = enforcer(event.target.value.replace(/,/g, '.'))
if (nextInput !== null) { if (nextInput !== null) {
setState(nextInput ?? '')
if (!isNumericallyEqual(nextInput, value)) {
onChange(nextInput) onChange(nextInput)
} }
}
}, },
[value, onChange, enforcer] [onChange, enforcer]
) )
return ( return (
<Input <Input
value={state} value={value}
onChange={validateChange} onChange={validateChange}
// universal input options // universal input options
inputMode="decimal" inputMode="decimal"
......
...@@ -95,9 +95,7 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr ...@@ -95,9 +95,7 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
[currencyIn, currencyOut, quoteResult, tradeType] [currencyIn, currencyOut, quoteResult, tradeType]
) )
const gasUseEstimateUSD = useStablecoinAmountFromFiatValue(quoteResult?.gasUseEstimateUSD) ?? null const gasUseEstimateUSD = useStablecoinAmountFromFiatValue(quoteResult?.gasUseEstimateUSD) ?? null
const trade = const trade = useMemo(() => {
useLast(
useMemo(() => {
if (route) { if (route) {
try { try {
return route && transformRoutesToTrade(route, tradeType, gasUseEstimateUSD) return route && transformRoutesToTrade(route, tradeType, gasUseEstimateUSD)
...@@ -106,9 +104,8 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr ...@@ -106,9 +104,8 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
} }
} }
return return
}, [gasUseEstimateUSD, route, tradeType]), }, [gasUseEstimateUSD, route, tradeType])
Boolean const lastTrade = useLast(trade, Boolean) ?? undefined
) ?? undefined
// Dont return old trade if currencies dont match. // Dont return old trade if currencies dont match.
const isStale = const isStale =
...@@ -125,9 +122,9 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr ...@@ -125,9 +122,9 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
if (isStale) { if (isStale) {
return { state: TradeState.LOADING, trade: undefined } return { state: TradeState.LOADING, trade: undefined }
} else if (isDebouncing) { } else if (isDebouncing) {
return { state: TradeState.SYNCING, trade } return { state: TradeState.SYNCING, trade: lastTrade }
} else if (isLoading) { } else if (isLoading) {
return { state: TradeState.LOADING, trade } return { state: TradeState.LOADING, trade: lastTrade }
} }
} }
...@@ -154,14 +151,15 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr ...@@ -154,14 +151,15 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
}, [ }, [
currencyIn, currencyIn,
currencyOut, currencyOut,
error,
quoteResult, quoteResult,
error,
route, route,
queryArgs, queryArgs,
trade, trade,
isStale, isStale,
isDebouncing, isDebouncing,
isLoading, isLoading,
lastTrade,
tradeType, tradeType,
]) ])
} }
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