Reputation: 1608
I recent upgraded my use-debounce react package. the breaking change was that the hook returned an object instead of an array. I am unable to update the hook so that it works with the new change. I have created a codesandbox to demonstrate the issue, where setting the state fails, as the setter returned from the hook isnt configured right. For the purpose of the sandbox, i threw the hook component inside the main component so all the info would be in one spot.
The error is setState is not a function
Heres the code from the sandbox if you dont feel like looking
const Input = () => {
// hook that would normally be in a seperate component
const useDebouncedState = (
initialState,
durationInMs = 200,
options = {}
) => {
const [internalState, setInternalState] = useState(initialState);
const debouncedSetter = useDebouncedCallback(
() => debouncedSetter.callback(setInternalState),
durationInMs,
options
);
return [internalState, debouncedSetter];
};
// this would be set in the main components
const [searchText, setSearchText] = useDebouncedState("", 200, {
maxWait: 1000
});
// this is where i set
return (
<>
<input type="text" onChange={(e) => setSearchText(e.target.value)} />
<h1>{searchText}</h1>
</>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<Input />, rootElement);
Upvotes: 1
Views: 411
Reputation: 1608
Thanks to all who posted, it led me to my answer. the working code is
import React, { useState } from "react";
import ReactDOM from "react-dom";
import useDebouncedCallback from "use-debounce/lib/useDebouncedCallback";
const Input = () => {
// hook that would normally be in a seperate component
const useDebouncedState = (
initialState,
durationInMs = 200,
options = {}
) => {
const [internalState, setInternalState] = useState(initialState);
const debouncedSetter = useDebouncedCallback(
setInternalState,
durationInMs,
options
);
return [internalState, debouncedSetter];
};
// this would be set in the main components
const [searchText, setSearchText] = useDebouncedState("", 800, {
maxWait: 1000
});
// this is where i set
return (
<>
<input
type="text"
onChange={(e) => setSearchText.callback(e.target.value)}
/>
<h1>{searchText}</h1>
</>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<Input />, rootElement);
Upvotes: 1
Reputation: 53874
The problem is with this code:
const debouncedSetter = useDebouncedCallback(
// debouncedSetter in this scope is undefined, but linter doesn't catch it
() => debouncedSetter(setInternalState),
durationInMs,
options
);
debouncedSetter
is undefined
since you never declared it, therefore due to closures it will call callback()
on undefined
which causes a runtime error.
If you change your code to the next snippet, you will notice the linting warnings:
const useDebouncedState = (initialState, durationInMs = 200, options = {}) => {
const [internalState, setInternalState] = useState(initialState);
const callback = useDebouncedCallback(
// 'debouncedSetter' is not defined
() => debouncedSetter(setInternalState),
durationInMs,
options
);
return [internalState, callback];
};
Upvotes: 2