This is how I would implement this hook :
function App() {
const { initialized, authObject, initAuth } = useAuth();
useEffect(() => {
if (!initialized) {
initAuth();
}
}, [initialized, initAuth]);
...
}
Or, better yet :
function App() {
const authObject = useAuth(); // let useAuth initialize itself
...
}
Typically, useAuth seems to be a multi-purpose hook, being used by various components, so it makes no sense to allow multiple components to call initAuth; the hook should only return the current state.
Preferably, you should implement that hook with a context
function App() {
return (
<AuthProvider>
<AppContent />
</AuthProvider>
);
}
function AppContent() {
const authObject = useAuth();
...
}
The contract, therefore, goes to the AuthProvider, and notifies every component using useAuth on state changes.
From OP's own answer, added some suggested improvements :
import React, { createContext, useContext, useState, useMemo } from "react";
const AuthContext = createContext({
isLoggedIn:false /* :Boolean */,
authObject:null /* :Object */,
login: (
username /* :String */,
password /* :String */
) /* :Preomise<Boolean> */ => {
throw new Error('Provider missing');
}
]);
const AuthContextProvider = ({ children }) => {
// init state with function so we do not trigger a
// refresh from useEffect. Use useEffect if the
// initial state is asynchronous
const [state, setState] = useState(() => {
const authObject = localStorage.getItem("authObject");
const isLoggedIn = !!authObject;
return { isLoggedIn, authObject };
});
// avoid refresh if state does not change
const contextValue = useMemo(() => ({
...state, // isLoggedIn, authObject
login: async (username, password) => {
// implement auth protocol, here
// do not expose setState directly in order to
// control what state is actually returned
// setState({ isLoggedIn:..., authObject:... });
// return true|false
}
}), [state]);
return (
<AuthContext.Provider value={ contextValue }>
{ children }
</AuthContext.Provider>
);
};
/**
Usage: const { isLoggedIn, authObject, login } = useAuthContext();
*/
const useAuthContext = () => useContext(AuthContext);
export { useAuthContext, AuthContextProvider };
initAuthwrapped inuseCallback?