Ошибка при попытке использования AuthStack для аутентификации пользователя

Вопрос или проблема

Я новичок в React Native, и у меня возникла проблема, когда я пытаюсь получить токен пользователя, чтобы проверить, аутентифицирован ли пользователь. Если токен найден, я считаю пользователя аутентифицированным и пытаюсь отобразить корневой стек. Однако проблема, с которой я сталкиваюсь, заключается в том, что экраны из AuthStack по-прежнему монтируются поверх RootStack. Можете, пожалуйста, помочь мне?

Ниже представлен мой код:

import { router, Slot, Stack, Tabs } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { useContext, useEffect, useState } from "react";
import { AuthContext, AuthContextProvider } from "../context/AuthContext";
import { ActivityIndicator, View } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { getUserInforWithToken } from "../controller/AuthController";
function RootStack() {
  return (
    <Stack>
      <Stack.Screen name="(root)/index" options={{ title: "Добро пожаловать" }} />
    </Stack>
  );
}
function AuthStack() {
  return (
    <Stack
      screenOptions={{
        headerStyle: { backgroundColor: "#6779ef" },
        headerTintColor: "white",
        contentStyle: { backgroundColor: "#6779ef" },
        headerShown: false,
      }}>
      <Stack.Screen name="(auth)/index" options={{ title: "Страница входа" }} />
      <Stack.Screen name="(auth)/signup" options={{ title: "Страница регистрации" }} />
    </Stack>
  );
}
function Root() {
  const { setIsLogin, setToken, setIsTryingLogin, isTryingLogin } =
    useContext(AuthContext);
  const [isLoading, setIsLoading] = useState(true);
  const { isLogin } = useContext(AuthContext);

  useEffect(() => {
    const checkAuth = async () => {
      const token = await AsyncStorage.getItem("token");
      if (token) {
        console.log("токен найден, пользователь вошел в систему");
        setIsLogin(true);
        setToken(token);
      } else {
        setIsLogin(false);
      }
      // Установить попытку входа в систему в false после проверки токена
      setIsTryingLogin(false);
    };

    checkAuth();
  }, []); // Это выполняется только один раз при монтировании компонента

  useEffect(() => {
    if (!isTryingLogin) {
      setIsLoading(false);
    }
  }, [isTryingLogin]);
  if (isLoading) {
    console.log("Загрузка...");
    return (
      <View className="flex-1 justify-center items-center">
       <ActivityIndicator className="p-2 m-2" animating size="large" />
      </View>
     );
   }
  return isLogin ? <RootStack /> : <AuthStack />;
}

export default function Layout() {
  return (
    <AuthContextProvider>
      <StatusBar style="light" />
      <Root />
    </AuthContextProvider>
  );
}

Я пробовал Chatgpt и читал документы, а также пытался следовать за кем-то на YouTube, но ничего не сработало.

Ответ или решение

На первый взгляд, ваша проблема заключается в том, что вы не контролируете восприятие стека навигации между AuthStack и RootStack должным образом. Вероятно, проблема заключается в том, что AuthStack и RootStack оба рендерятся одновременно, поэтому экраны из AuthStack накладываются на экраны из RootStack.

Есть несколько вещей, которые вы можете попробовать, чтобы решить эту проблему:

  1. Правильный контроль состояния аутентификации: Убедитесь, что состояние аутентификации корректно обрабатывается в компоненте Root. Ваш код в целом выглядит хорошо, однако контроль за состоянием isLogin и условия рендеринга могут быть улучшены.

  2. Структура навигации: Вместо того, чтобы возвращать AuthStack или RootStack в зависимости от состояния аутентификации, вы можете использовать условную логику внутри одного стека, чтобы контролировать навигацию более эффективно.

Вот пример, как вы можете изменить ваш компонент Root, чтобы избежать накладок экранов:

function Root() {
  const { setIsLogin, setToken, setIsTryingLogin, isTryingLogin } = useContext(AuthContext);
  const [isLoading, setIsLoading] = useState(true);
  const { isLogin } = useContext(AuthContext);

  useEffect(() => {
    const checkAuth = async () => {
      const token = await AsyncStorage.getItem("token");
      if (token) {
        console.log("token found, user logged in");
        setIsLogin(true);
        setToken(token);
      } else {
        setIsLogin(false);
      }
      setIsTryingLogin(false);
    };

    checkAuth();
  }, []);

  useEffect(() => {
    if (!isTryingLogin) {
      setIsLoading(false);
    }
  }, [isTryingLogin]);

  if (isLoading) {
    console.log("Loading...");
    return (
      <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
        <ActivityIndicator style={{ padding: 2, margin: 2 }} animating size="large" />
      </View>
    );
  }

  // Основное изменение здесь
  return (
    <Stack>
      {isLogin ? <RootStack /> : <AuthStack />}
    </Stack>
  );
}
  1. Использование React Navigation: Если вы еще не используете его, возможно, вам стоит рассмотреть возможность использования пакета @react-navigation/native, который предоставляет более удобные инструменты для работы с навигацией в приложении React Native. Это может облегчить создание и управление стеками навигации.

  2. Тестирование переходов: Убедитесь, что ваше состояние аутентификации действительно меняется в ожидаемые моменты. Вы можете добавить консольные логирования для isLogin и состояния загрузки, чтобы убедиться, что логика работает так, как задумано.

Эти изменения должны помочь предотвратить наложение экранов аутентификации и корневого стека навигации. Если проблема сохраняется, стоит проверить, возможно ли наличие дополнительных факторов, таких как ошибки в других частях вашего кода.

Оцените материал
Добавить комментарий

Капча загружается...