Почему мое реагирующее нативное выставочное приложение не получает контекст от AuthProvider?Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Почему мое реагирующее нативное выставочное приложение не получает контекст от AuthProvider?

Сообщение Anonymous »

Эта проблема возникла у меня уже довольно давно, я пробовал все, что мог, чтобы ее исправить, но ничего не помогло.
Вот содержимое AuthContext.tsx:

Код: Выделить всё

import React, {
createContext,
useContext,
useEffect,
useState,
ReactNode,
} from "react";
import axios from "axios";
import * as SecureStore from "expo-secure-store";
import { ActivityIndicator } from "react-native-paper";
import { jwtDecode } from "jwt-decode";

type AuthContextType = {
onRegister: (username: string, password: string) => Promise;
onLogin: (username: string, password: string) => Promise;
onLogout: () => Promise;
authState: AuthStateType;
authData: AuthDataType;
};

type AuthStateType = {
token: string | null;
authenticated: boolean;
};

type AuthDataType = {
id: number | null;
username: string | null;
iat: number | null;
exp: number | null;
};

const AuthContext = createContext(undefined);

const TOKEN_KEY = "authToken";
const API_URL = "https://anonytext-backend.vercel.app/api";

const useAuth = (): AuthContextType => {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
};

type AuthProviderProps = {
children: ReactNode;
};

const AuthProvider: React.FC = ({ children }) => {
const [loading, setLoading] = useState(true);
const [authState, setAuthState] = useState({
token: null,
authenticated: false,
});
const [authData, setAuthData] = useState({
id: null,
username: null,
iat: null,
exp: null,
});

const register = async (username: string, password: string): Promise => {
try {
return await axios.post(`${API_URL}/auth/register`, {
username,
password,
});
} catch (e: any) {
return {
error: true,
message: e.response?.data?.message || "An error occurred",
};
}
};

const login = async (username: string, password: string): Promise => {
try {
const result = await axios.post(`${API_URL}/auth/login`, {
username,
password,
});
setAuthState({ token: result.data.access, authenticated: true });
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${result.data.access}`;
await SecureStore.setItemAsync(TOKEN_KEY, result.data.access);

return result;
} catch (e: any) {
return {
error: true,
message: e.response?.data?.message || "An error occurred",
};
}
};

const logout = async (): Promise => {
await SecureStore.deleteItemAsync(TOKEN_KEY);
axios.defaults.headers.common["Authorization"] = "";
setAuthState({ token: null, authenticated: false });
};

useEffect(() => {
const loadToken = async () =>  {
const token = await SecureStore.getItemAsync(TOKEN_KEY);

if (token) {
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
setAuthState({ token, authenticated: true });
setAuthData(jwtDecode(token));
}
setLoading(false);
};

loadToken();
}, []);

const contextData: AuthContextType = {
onRegister: register,
onLogin: login,
onLogout: logout,
authState,
authData,
};

return (

{!loading ? children : }

);
};

export { AuthProvider, useAuth };
Это выглядит довольно солидно и должно работать, но я продолжаю получать

Код: Выделить всё

(NOBRIDGE) ERROR  Warning: Error: useAuth must be used within an AuthProvider

This error is located at:
in RootLayout
in Unknown (created by Route())
in Suspense (created by Route())
in Route (created by Route())
in Route() (created by ContextNavigator)
in RNCSafeAreaProvider (created by SafeAreaProvider)
in SafeAreaProvider (created by wrapper)
in wrapper (created by ContextNavigator)
in ThemeProvider
in EnsureSingleNavigator
in BaseNavigationContainer
in NavigationContainerInner (created by ContextNavigator)
in ContextNavigator (created by ExpoRoot)
in ExpoRoot (created by App)
in App (created by ErrorOverlay)
in ErrorToastContainer (created by ErrorOverlay)
in ErrorOverlay (created by withDevTools(ErrorOverlay))
in withDevTools(ErrorOverlay)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent)
Согласно этому сообщению, перехват useAuth должен использоваться в дочернем элементе, обернутом контекстом AuthProvider, что я и сделал здесь:
App.tsx:

Код: Выделить всё

import React from "react";
import { AuthProvider } from "@/context/AuthContext";
import RootLayout from "./app/_layout";
import { NotifierWrapper } from "react-native-notifier";
import { GestureHandlerRootView } from "react-native-gesture-handler";

// Wrap the entire app with AuthProvider
export default function App() {
return (







);
}
И ./app/_layout.tsx:

Код: Выделить всё

import React, { useCallback } from "react";
import { Slot, Redirect } from "expo-router";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { useFonts } from "expo-font";
import * as SplashScreen from "expo-splash-screen";
import { useAuth } from "@/context/AuthContext";
import { ActivityIndicator } from "react-native-paper";

// Prevent the splash screen from hiding until the font is loaded
SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
const { authState } = useAuth(); // Directly access authState from context

console.log("Auth Context State:", authState);

const [fontsLoaded] = useFonts({
FontAwesome6Pro: require("../assets/fonts/fa-regular-400.ttf"),
FontAwesome6ProLight: require("../assets/fonts/fa-light-300.ttf"),
FontAwesome6ProSolid: require("../assets/fonts/fa-solid-900.ttf"),
});

const onLayoutRootView = useCallback(async () => {
if (fontsLoaded) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded]);

if (!fontsLoaded) {
return null; // Keep splash screen visible while loading fonts
}

// If authState is undefined, don't attempt to render protected routes yet
if (authState === undefined) {
return ; // Show loading indicator if auth state is undefined
}

return (

{authState.authenticated ?  : }

);
}
Это должно работать, потому что я обернул RootLayout с помощью AuthProvider.
Я что-то сделал не так?

Подробнее здесь: https://stackoverflow.com/questions/791 ... thprovider
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»