Skip to content

Commit

Permalink
[Improvement] Debounce amount input to reduce rpc calls #2526 (#2527)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielisaacgeslin authored Sep 16, 2024
1 parent 5d898d6 commit 7d52f33
Showing 1 changed file with 52 additions and 10 deletions.
62 changes: 52 additions & 10 deletions wormhole-connect/src/views/v2/Bridge/AmountInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, {
useCallback,
useMemo,
useState,
ComponentProps,
memo,
useEffect,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import { useDebounce } from 'use-debounce';
import { usePrevious } from 'utils';
import { useTheme } from '@mui/material';
import Button from '@mui/material/Button';
import Card from '@mui/material/Card';
Expand All @@ -18,7 +26,47 @@ import { setAmount } from 'store/transferInput';
import { getMaxAmt, validateAmount } from 'utils/transferValidation';
import type { TokenConfig } from 'config/types';
import type { RootState } from 'store';
import { usePrevious } from 'utils';

const INPUT_DEBOUNCE = 300;

const DebouncedTextField = memo(
({
value,
onChange,
...props
}: Omit<ComponentProps<typeof TextField>, 'onChange' | 'value'> & {
value: string;
onChange: (event: string) => void;
}) => {
const [innerValue, setInnerValue] = useState<string>(value);
const [deferredValue] = useDebounce(innerValue, INPUT_DEBOUNCE);
const prev = usePrevious(deferredValue);

const onInnerChange = useCallback(
(
e: Parameters<
NonNullable<ComponentProps<typeof TextField>['onChange']>
>[0],
) => {
if (Number(e.target.value) < 0) return; // allows "everything" but negative numbers
setInnerValue(e.target.value);
},
[],
);

useEffect(() => {
if (prev !== deferredValue && deferredValue !== value) {
onChange(deferredValue);
}
}, [onChange, deferredValue, prev, value]);

useEffect(() => {
setInnerValue(value);
}, [value]);

return <TextField {...props} value={innerValue} onChange={onInnerChange} />;
},
);

const useStyles = makeStyles()((theme) => ({
amountContainer: {
Expand Down Expand Up @@ -148,20 +196,14 @@ const AmountInput = (props: Props) => {
);
}, [isInputDisabled, tokenBalance]);

// Update token amount in local state
const onAmountChange = useCallback((e: any) => {
if (Number(e.target?.value) < 0) return; // allows "everything" but negative numbers
setAmountLocal(e.target?.value);
}, []);

return (
<div className={classes.amountContainer}>
<div className={classes.amountTitle}>
<Typography variant="body2">Amount:</Typography>
</div>
<Card variant="elevation">
<CardContent className={classes.amountCardContent}>
<TextField
<DebouncedTextField
fullWidth
disabled={isInputDisabled}
inputProps={{
Expand All @@ -177,7 +219,7 @@ const AmountInput = (props: Props) => {
placeholder="0"
variant="standard"
value={amountLocal}
onChange={onAmountChange}
onChange={setAmountLocal}
onWheel={(e) => {
// IMPORTANT: We need to prevent the scroll behavior on number inputs.
// Otherwise it'll increase/decrease the value when user scrolls on the input control.
Expand Down

0 comments on commit 7d52f33

Please sign in to comment.