钩子获取的变量没有在组件中更新



我有一个钩子,通过存储在localstorage用户信息来处理登录客户端。一切正常,只是在使用login方法

后,组件中由该钩子检索的用户没有更新。
const useAuth = () => {
const localStorageUserKey = "@mysite:user"
const [user, setUser] = useState<IUser | null>(null);
const navigate = useNavigate();
useEffect(() => {
const userJson = window.localStorage.getItem(localStorageUserKey);
if (userJson) {
setUser(JSON.parse(userJson));
}
}, []);
const login = (newUser: IUser) => {
window.localStorage.setItem(localStorageUserKey, JSON.stringify(newUser));
setUser(newUser);
}
const logout = () => {
window.localStorage.removeItem(localStorageUserKey);
setUser(null);
navigate("/");
}
return { login, logout, user }
}
export default useAuth;

我是这样用的


export default function LoginPage() {
const { post } = useApi();
const { login } = useAuth();
const [error, setError] = useState<string>("");
const navigate = useNavigate()
const onSubmit = (email: string, password: string) => {
setError("");
post<ILoginApiResponse>("/login", { email, password }).then((r) => {
if (r.data.user) {
login(r.data.user);
}
}).catch((r) => {
if (r.response.status === 400) {
setError("Identifiants invalides");
} else {
setError("Une erreur est survenue");
}
});
}
return (
<div>
<h2>Connexion</h2>
{error ? <ErrorMessage message={error} /> : null}
<LoginForm onSubmit={onSubmit} />
</div>
);
}

和一个使用user

的例子
export default function Layout(props: ILayoutProps) {
const { user, logout } = useAuth();
return <div className={"main-container"}>
<header className="header-container">
<nav>
<ul className={"header-nav"}>
/* ... */
{!user ? 
<li className={"item"}>
<a className={"header-nav-link"} href="/login">Connexion</a>
</li> : 
<li>
<button className={"header-nav-link"} onClick={logout}>Se déconnecter</button>
</li>
}
</ul>
</nav>
</header>
<Outlet />
</div>;
}

User是在localstorage中设置的,并在hook中更新(尝试使用useEffect),而不是在检索它的组件中更新。

知道为什么吗?谢谢!

钩子是封装和隔离的逻辑单元,可以从各种组件调用。从LoginPage中调用的useAuth状态下存储的数据与Layout中调用的数据不同。想象一下,如果你从钩子中取出逻辑,然后把它分别放在两个组件中,会发生什么?

自定义钩子用于封装可重用逻辑,而不是状态。要封装可重用状态,你可以使用React内置的Context API。然后,自定义钩子可以提供对该上下文的访问,但这不是必需的。

export const AuthContext = React.createContext<ContextState>(defaultContextValues);
export function ContextProvider({ children }: PropsWithChildren) {
const [user, setUser] = useState<IUser | null>(null);
const login = () => { ... };
const logout = () => { ... };
return <AuthContext.Ptovider values={{ 
user,
login,
logout,
}}
>
{children}
</AuthContext.Provider>
};
export function useAuth() {
return React.useContext(AughContext);
};

现在您的整个状态保存在一个地方,children中的所有组件都可以通过调用useAuth来使用它。记得用AuthProvider来包装你的应用。

export function App() {
return (
<AuthProvider>
{/* components go here */}
</AuthProvider>
);
};

最新更新