我有一个钩子,通过存储在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>
);
};