我正在为我的应用程序创建一个
register
屏幕,为此,我创建了一个 OnAuth 挂钩,用于注册登录/注册和注销功能,并管理经过身份验证的状态以及用户。
interface authProperties {
user: {user: any};
isAuthenticated: boolean;
register: (
email: string,
password: string,
firstname: string,
lastname: string,
) => Promise<any>;
login: (email: string, password: string) => Promise<any>;
logout: () => Promise<any>;
}
export const authContext = createContext<authProperties>({} as authProperties);
export const AuthProvider = ({children}: any) => {
const [user, setUser] = useState<{user: any}>({user: null});
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, user => {
console.log('AuthProvider effect triggered', user);
if (user) {
setIsAuthenticated(true);
setUser({user});
} else {
setIsAuthenticated(false);
setUser({user: null});
}
});
return unsubscribe;
}, []);
const login = async (email: string, password: string) => {
// login logic
};
const register = async (
email: string,
password: string,
firstname: string,
lastname: string,
) => {
// register logic
};
const logout = async () => {
// logout logic
};
const value = {
user,
isAuthenticated,
register,
login,
logout,
};
return <authContext.Provider value={value}>{children}</authContext.Provider>;
};
export const useAuth = () => {
const value = useContext(authContext);
if (!value) {
throw new Error('useAuth must be used within an AuthProvider');
}
return value;
};
然后在我的
App.tsx
中,我设置了一个 useEffect 以在 isAuthenticated 更改时触发。
const App = () => {
// new auth state
const {isAuthenticated} = useAuth();
useEffect(() => {
console.log('App useEffect triggered');
if (isAuthenticated) {
console.log('User is authenticated');
} else {
console.log('User is not authenticated');
}
}, [isAuthenticated]);
return (
<AuthProvider>
{isAuthenticated ? (
<TabNavigator />
) : (
<SafeAreaProvider>
<NavigationContainer>
<Routes />
</NavigationContainer>
</SafeAreaProvider>
)}
</AuthProvider>
);
};
export default App;
当我注册新用户时,我的
authprovider
内的效果被正确触发。我在输入和注册时收到日志,我收到正确的 firebase 用户、令牌等。
但是,我预计
isAuthenticated
上的 useEffect 也会被触发。从这里开始,我希望有逻辑转到选项卡导航器(经过身份验证时)或签名/注册(未经身份验证时)
我对原生反应相对较新,不确定为什么没有触发此效果。
如果有人知道,将不胜感激!
App
组件正在访问ReactTree中在其上方渲染的someAuthProvider
组件的上下文,而不是它自身渲染的组件。既然您抱怨或询问为什么不抛出 'useAuth must be used within an AuthProvider'
,我假设有多个 AuthProvider
正在渲染,并且实际上上面有一个 App
。
每个应用程序可能只需要一个
AuthProvider
组件,因此整个应用程序访问相同的单个提供的上下文值。您可以删除 AuthProvider
渲染的无关 App
组件。
<AuthProvider>
<App />
</AuthProvider>
useContext
钩子的首选方法。const App = () => {
// new auth state
const { isAuthenticated } = useAuth();
useEffect(() => {
console.log('App useEffect triggered');
if (isAuthenticated) {
console.log('User is authenticated');
} else {
console.log('User is not authenticated');
}
}, [isAuthenticated]);
return isAuthenticated
? <TabNavigator />
: (
<SafeAreaProvider>
<NavigationContainer>
<Routes />
</NavigationContainer>
</SafeAreaProvider>
);
};
export default App;
万一,
AuthProvider
组件App
渲染是,并且实际上存在一些错误,那么要么在ReactTree中将AuthProvider
移动到比App
更高的位置,这样App
可以访问。
您还可以使用 Context Consumer 有条件地渲染导航器或路线。这仍然假设
AuthProvider
组件在 ReactTree 和 App
中渲染得更高。
示例:
const App = () => {
return (
<authContext.Consumer>
{({ isAuthenticated }) => {
return isAuthenticated
? <TabNavigator />
: (
<SafeAreaProvider>
<NavigationContainer>
<Routes />
</NavigationContainer>
</SafeAreaProvider>
);
}}
</authContext.Consumer>
);
};