Почему мое реагирующее нативное выставочное приложение не получает контекст от 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 Предупреждение: ошибка : useAuth должен использоваться внутри AuthProvider

Согласно этому сообщению, хук 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»