Can anyone point help me to find out why onChange
is never being executed?
Basically I’m extending ChakraUI’s Input
component to load a value from localStorage if such value exists.
The component is correctly loading the localStorage value, but if I try to set the value
property from the value
state, the component becomes read-only, which means it’s an uncontrolled component & etc, but defaultValue
is supposed to circumvent this. What is the matter here?
I even tried a hack using an useEffect
hook to read localStorage and then directly update the input using classic JavaScript DOM manipulation. It correctly updates the value but still doesn’t trigger onChange
.
I also tried using onBlur
instead to avoid any potential problems from re-renders, which wasn’t being triggered as well.
What am I doing wrong?
import { ChangeEvent, useState, forwardRef } from 'react';
import { Input, InputProps } from '@chakra-ui/react';
interface StoredInputProps {
name: string;
defaultValue?: string;
placeholder?: string ;
autoCapitalize?: string;
}
type CombinedInputProps = StoredInputProps & InputProps;
const StoredInput= forwardRef<HTMLInputElement, CombinedInputProps>(
({ name, defaultValue = '', placeholder = '', autoCapitalize = 'none', ...props }, ref) => {
const [value, setValue] = useState<string>(() => {
const storedValue = localStorage.getItem(name);
return storedValue !== null ? storedValue : defaultValue;
});
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
console.log("Handle Change")
const newValue = event.target.value;
// Immediately update localStorage when the value changes
localStorage.setItem(name, newValue);
};
return (
<>
<Input
id={name}
name={name}
defaultValue={value}
onChange={(event) => handleChange(event)}
placeholder={placeholder}
autoCapitalize={autoCapitalize}
{...props}
/>
</>
);
});
export default StoredInput;
2
Answers
The
{...props}
destructuring at the end of the component was overwriting my own value foronChange
. Moving it to the top declaration solved the issue.The useState doesn’t change each time the storage value change.
A better idea would be to set the value of directly after you set the storage value.
This is how you would implement it:
Also you can use a
useEffect
but it would be a wast of time.I hope this answer will help you