自定义Hook中useEffect未因其他Hook依赖变更触发问题
问题:自定义Hook状态无法跨组件同步,useEffect不触发
我有一个自定义Hook useProvideAuth,用于管理accessToken状态和更新方法:
export function useProvideAuth() { const [accessToken, setAccessToken] = useState<string>( "noToken" ); const setAuth = (newToken: string) => { // 注:为简化未包含完整逻辑 setAccessToken(newToken); }; return { accessToken, setAccessToken: setAuth }; };
随后在另一个自定义Hook useMyUserDetails 中使用它,并将accessToken作为useEffect的依赖:
export function useMyUserDetails() { const { accessToken } = useProvideAuth(); useEffect(() => { // 执行相关操作 // 当accessToken变更时,此useEffect从未被调用 }, [accessToken]); }
遇到的问题:useMyUserDetails中的useEffect仅在初始时执行一次,accessToken变更时完全不触发。调用setAccessToken的组件内accessToken确实已更新,但useMyUserDetails中的accessToken始终未变化。
原因分析
每个组件或自定义Hook调用useProvideAuth时,都会创建独立的useState状态实例。也就是说,调用setAuth的组件里的accessToken,和useMyUserDetails里的accessToken是两个互不相干的状态,自然无法同步更新。
解决方案:用React Context共享状态
要实现跨组件/Hook的状态同步,需要用React Context来统一管理Auth状态,让所有消费它的组件共享同一个状态实例。
1. 创建Auth Context与Provider
// auth-context.tsx import { createContext, useContext, useState, ReactNode } from 'react'; // 定义Context的类型 type AuthContextType = { accessToken: string; setAuth: (newToken: string) => void; }; // 创建Context,默认值仅用于类型提示 const AuthContext = createContext<AuthContextType | undefined>(undefined); // 实现Provider组件,统一管理状态 export function AuthProvider({ children }: { children: ReactNode }) { const [accessToken, setAccessToken] = useState<string>("noToken"); const setAuth = (newToken: string) => { // 可在此添加完整逻辑(如存入localStorage) setAccessToken(newToken); }; return ( <AuthContext.Provider value={{ accessToken, setAuth }}> {children} </AuthContext.Provider> ); } // 自定义Hook用于安全消费Context export function useProvideAuth() { const context = useContext(AuthContext); if (!context) { throw new Error('useProvideAuth必须在AuthProvider内部使用'); } return context; }
2. 改造useMyUserDetails
现在调用useProvideAuth会拿到共享的全局状态,状态更新时useEffect会正常触发:
export function useMyUserDetails() { const { accessToken } = useProvideAuth(); useEffect(() => { console.log('accessToken已更新:', accessToken); // 执行你的业务操作 }, [accessToken]); }
3. 在根组件中包裹Provider
确保所有需要共享Auth状态的组件都被AuthProvider包裹:
// App.tsx import { AuthProvider } from './auth-context'; import TokenSetterComponent from './TokenSetterComponent'; // 调用setAuth的组件 import UserDetailsComponent from './UserDetailsComponent'; // 使用useMyUserDetails的组件 function App() { return ( <AuthProvider> <TokenSetterComponent /> <UserDetailsComponent /> </AuthProvider> ); } export default App;
这样修改后,任何组件调用setAuth更新accessToken时,所有消费useProvideAuth的地方都会同步拿到最新值,对应的useEffect也会触发执行。
内容的提问来源于stack exchange,提问作者dragan14
相关产品推荐
相关产品推荐

