Hook does not re-initialise when key is not a constant
atiredturtle opened this issue · 4 comments
Calling the useLocalStorage hook with a non-constant key causes errors.
This is an issue in the case someone wishes to make a custom hook that is built on top of useLocalStorage.
Example
This is a bit contrived, and one would probably not write code like this, but it's the simplest way I can demonstrate the bug.
In this example, we have a custom hook using useLocalStorage with a parameter name as input. We have some asyncAge parameter that we know is resolved when asyncAge.pending is true.
const useAgeEdit = (name, asyncAge) => {
const [age, setAge] = useLocalStorage(name, 0);
// A use effect hook that will set the age based on the asyncAge value passed in
useEffect(() => {
if (!asyncAge.pending && !age) {
setAge(asyncAge.age)
}
}, [asyncAge])
return [age, setAge]
}
This hook does not work currently, as useLocalStorage does not change when the params in change. The only way around this currently is to forcefully re-render a component so that the hook initialises.
Hello, does this look like a valid test case?
https://github.com/rehooks/local-storage/blob/issue/38/test/index.test.tsx#L192-L216
I am not sure if I am reproducing the problem correctly. To me this seems ok (apart from the react-testing-library complaining about calling waitForNextUpdate
within an act
)
Not quite. The issue I've found seems to be on the hook not updating the age
and setAge
variables when we create a new instance of it.
Here's an example I created for myself to test it
import React, {useState} from "react";
import { useLocalStorage } from "../src/index";
// key prop needs to change
const EditAge = ({name}) => {
let [age, setAge] = useLocalStorage(name, 0);
return (
<div>
<h1>Currently Editing {name}'s Age</h1>
<input type="number" value={age} onChange={event => setAge(parseInt(event.target.value) || age)}/>
</div>
)
}
export default () => {
const allPeople = ["Tim", "Bob", "Gemma"]
const [editPerson, setEditPerson] = useState(undefined);
return (
<div>
<EditAge name={editPerson}/>
{allPeople.map(name => <button onClick={() => setEditPerson(name)} key={name}>{name}</button>)}
</div>
);
}
If you run it, you'll notice that if you edit an age, and then click on a different name, the age stays the same (since the hook doesn't update on props change)
Seems like it has to do with passing 0 as the default value.