I have 2 custom hooks. one is to handling token (useToken) and another is for just decoding user by token (useUser). Now I want updated token each time in my custom-hook useUser but it never triggers, I have added [token] as dependency but no useEffect call.
import { useState, useEffect } from "react";
function getToken() {
return window.localStorage.getItem("token");
}
function useToken() {
const [token, updateToken] = useState(() => getToken());
const setToken = (newToken) => {
localStorage.setItem("token", newToken);
updateToken(newToken);
};
return [token, setToken];
}
const getUserFromToken = (token) => {
if (!token) return null;
return token + Date().toString();
};
function useUser() {
const [token] = useToken();
const [user, setUser] = useState(() => getUserFromToken(token));
useEffect(() => {
if (!token) return;
const newUser = getUserFromToken(token);
setUser(newUser);
}, [token]);
return user;
}
export default function App() {
const [token, setToken] = useToken();
const user = useUser();
const [userName, setUserName] = useState("");
const handleChange = (e) => setUserName(e.target.value);
const saveHandler = () => {
setToken(userName);
};
return (
<div className="App">
<div>
<input
type="text"
placeholder="Enter Username"
value={userName}
onChange={handleChange}
/>
<button onClick={saveHandler}>Save</button>
</div>
<div>User - {user}</div>
</div>
);
}
I also tried by using useMemo instead useEffect in useUser hook but none of are working. Whats wrong going here?
Allow me to explain what's happening. Your custom hook useUser
is using it's own version of the useToken
hook. So when your actual token is updated inside App
by calling setToken
, it only updates the token
inside the App
component.
Notice the hook useUser
still has its own version of the token even though you updated the token in App
. Custom hooks don't magically talk to each other unless something like useContext is used.
The fix will be simple. We will pass the App's token to the useUser
hook and everything will work.
function useUser(token) {
const [user, setUser] = useState(() => getUserFromToken(token));
useEffect(() => {
if (!token) return;
const newUser = getUserFromToken(token);
setUser(newUser);
}, [token]);
return user;
}
// In App
const [token, setToken] = useToken();
const user = useUser(token);
I would however like to offer another piece of advice. I can see the useUser
hook doesn't really do much. It basically processes whatever token
it gets and spills out a user
without performing any actions. For this use case, maintaining a separate state and using useEffect
inside useUser
seems to be unnecessary. Since user
is always derived from the token this seems to a good case to use useMemo
.
The useUser
can thus be simplified as follows:
function useUser(token) {
const user = useMemo(() => getUserFromToken(token), [token]);
return user;
}
I hope all of this made sense. :)