0
\$\begingroup\$

I need people who have experience with React to review my code.

I want to make a debounce using Lodash.

import debounce from 'lodash/debounce'
const [name, setName] = React.useState<string | undefined>(undefined)
const [displayedName, setDisplayedName] = React.useState<string | undefined>(undefined)

const changeName = debounce((e: domProperty) => {
  setName(e.target.value)
}, 1000)

React.useEffect(() => {
  // call API
}, [name])
return (
  <Input
    placeholder="Player name"
    prefix={<UserOutlined />}
    value={displayedName}
    onChange={(e) => {
      changeName(e);
      setDisplayedName(e.target.value);
    }}
  />
)

Is it good? or is there anything wrong there?

So here I use displayedName because when I type something in Input, the name state doesn't change as it might be blocked by a debounce.

For example: when I type "alex" at the beginning (it works), then when I want to add the letter "i" (it doesnt, so I can't add or remove any letter it always "alex"), the name state is still the same as "alex". Therefore I add displayedName.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$
  1. Code you provided can't work properly in some cases. Thing is that debounce returns a completely new function with a separate queue on each new render.
    • So, in case if rerender happens, changeName will be completely new & will apply changes immediately
    • There is an even worse possibility. As the old debounced function is not destroyed, it can overwrite the value written by the new changeName.
    • In order to fix that, you need to wrap it into React.useMemo. Like React.useMemo(debounce(e => { … }, 1000), [])
  2. Consider using a special hook https://usehooks.com/useDebounce/

useDebounce

I will take code here of useDebounce function from cited article:

function useDebounce(value, delay) {
    const [debouncedValue, setDebouncedValue] = useState(value);

    useEffect(
        () => {
            const handler = setTimeout(() => setDebouncedValue(value), delay);

            return () => clearTimeout(handler);
        },
        [value, delay]
    );
    
    return debouncedValue;
}

And in your code usage is going to look like:

const [name, setName] = React.useState<string | undefined>(undefined);
const debouncedName = useDebounce(name, 1000);

const changeName = ((e: domProperty) => {
    setName(e.target.value)
};

React.useEffect(() => {
    // call API
}, [debouncedName])

return (
    <Input
        placeholder="Player name"
        prefix={<UserOutlined />}
        value={displayedName}
        onChange={(e) => {
            changeName(e);
        }}
    />
)

This is more beautiful because you don't need to write the value into two state variables.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.