admin管理员组

文章数量:1410712

I have a problem with "@react-native-async-storage/async-storage" lib. my app is expo react-native project, with latest 52 SDK. The problem is, on web it working fine, but on android causing hooks order error. this error also have apperead on secure store package. here it is:

Warning: React has detected a change in the order of Hooks called by MainLayout. This 
will lead to bugs and errors if not fixed. For more information, read the Rules of 
Hooks: /link/rules-of-hooks

Previous render            Next render
   ------------------------------------------------------
1. useState                   useState
2. useEffect                  useEffect
3. useContext                 useContext
4. useSyncExternalStore       useMemo
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    in MainLayout
    in Unknown (created by Route((main)))
    in Suspense (created by Route((main)))
    in Route (created by Route((main)))
    in Route((main)) (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by SlotNavigator)
    in PreventRemoveProvider (created by NavigationContent)
    in NavigationContent
    in Unknown (created by SlotNavigator)
    in SlotNavigator (created by Slot)
    in Slot (created by AuthRoutes)
    in AuthRoutes (created by RootLayout)
    in PortalProviderComponent (created by BottomSheetModalProviderWrapper)
    in BottomSheetModalProviderWrapper (created by RootLayout)
    in RNGestureHandlerRootView (created by GestureHandlerRootView)
    in GestureHandlerRootView (created by RootLayout)
    in BottomSheetContextProvider (created by RootLayout)
    in ApplicationContextProvider (created by RootLayout)
    in AuthContextProvider (created by RootLayout)
    in RNGestureHandlerRootView (created by GestureHandlerRootView)
    in GestureHandlerRootView (created by RootLayout)
    in ThemeContextProvider (created by RootLayout)
    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)

Library usage example in file:

import AsyncStorage from "@react-native-async-storage/async-storage";
import { useRouter } from "expo-router";
import { useEffect, useState } from "react";
import Toast from "react-native-toast-message";
import { login as apiLogin, logout as apiLogout, verify as apiVerify } from "../api";

export const useAuth = () => {
    const [isAuth, setIsAuth] = useState<boolean | "pending">("pending");
    const [token, setToken] = useState<string | null>(null);

    const router = useRouter();
    const login = async (data: { phone: string; password: string }, rememberMe: boolean) => {
        try {
            const res = await apiLogin(data);

            await AsyncStorage.setItem("token", res.result.token);
            await AsyncStorage.setItem("refresh_token", res.result.refresh_token);

            setIsAuth(true);
            setToken(res.result.token);
            router.replace("/info");
        } catch (e) {
            Toast.show({
                type: "error",
                text1: e as string,
            });
        }
    };
    const logout = async () => {
        try {
            const token = (await AsyncStorage.getItem("token")) as string;
            await apiLogout(token);
        } catch (e) {
            Toast.show({
                type: "error",
                text1: e as string,
            });
        }
        await AsyncStorage.removeItem("token");
        await AsyncStorage.removeItem("refresh_token");

        setIsAuth(false);
        setToken(null);
        router.replace("/auth");
    };
    const verify = async () => {
        try {
            const token = await AsyncStorage.getItem("token");
            if (token) {
                const res = await apiVerify(token);

                if (res.ok && res.result) {
                    setToken(token);
                    return setIsAuth(true);
                } else {
                    setToken(null);
                    return await logout();
                }
            }
            await logout();
        } catch (e) {
            await logout();
            Toast.show({
                type: "error",
                text1: e as string,
            });
        }
    };

    useEffect(() => {
        const effectWrapper = async () => {
            const token = await AsyncStorage.getItem("token");
            if (token !== null) {
                verify();
            } else {
                setIsAuth(false);
            }
        };
        effectWrapper();
    }, []);

    return { login, logout, verify, setIsAuth, isAuth, token };
};

I tried different storage libs, tried 51 SDK, tried call lib functions in clean project, tried use only in useEffect/useCallback/event handlers/etc. errors doesnt disaper. please help

I have a problem with "@react-native-async-storage/async-storage" lib. my app is expo react-native project, with latest 52 SDK. The problem is, on web it working fine, but on android causing hooks order error. this error also have apperead on secure store package. here it is:

Warning: React has detected a change in the order of Hooks called by MainLayout. This 
will lead to bugs and errors if not fixed. For more information, read the Rules of 
Hooks: https://react.dev/link/rules-of-hooks

Previous render            Next render
   ------------------------------------------------------
1. useState                   useState
2. useEffect                  useEffect
3. useContext                 useContext
4. useSyncExternalStore       useMemo
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    in MainLayout
    in Unknown (created by Route((main)))
    in Suspense (created by Route((main)))
    in Route (created by Route((main)))
    in Route((main)) (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by SlotNavigator)
    in PreventRemoveProvider (created by NavigationContent)
    in NavigationContent
    in Unknown (created by SlotNavigator)
    in SlotNavigator (created by Slot)
    in Slot (created by AuthRoutes)
    in AuthRoutes (created by RootLayout)
    in PortalProviderComponent (created by BottomSheetModalProviderWrapper)
    in BottomSheetModalProviderWrapper (created by RootLayout)
    in RNGestureHandlerRootView (created by GestureHandlerRootView)
    in GestureHandlerRootView (created by RootLayout)
    in BottomSheetContextProvider (created by RootLayout)
    in ApplicationContextProvider (created by RootLayout)
    in AuthContextProvider (created by RootLayout)
    in RNGestureHandlerRootView (created by GestureHandlerRootView)
    in GestureHandlerRootView (created by RootLayout)
    in ThemeContextProvider (created by RootLayout)
    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)

Library usage example in file:

import AsyncStorage from "@react-native-async-storage/async-storage";
import { useRouter } from "expo-router";
import { useEffect, useState } from "react";
import Toast from "react-native-toast-message";
import { login as apiLogin, logout as apiLogout, verify as apiVerify } from "../api";

export const useAuth = () => {
    const [isAuth, setIsAuth] = useState<boolean | "pending">("pending");
    const [token, setToken] = useState<string | null>(null);

    const router = useRouter();
    const login = async (data: { phone: string; password: string }, rememberMe: boolean) => {
        try {
            const res = await apiLogin(data);

            await AsyncStorage.setItem("token", res.result.token);
            await AsyncStorage.setItem("refresh_token", res.result.refresh_token);

            setIsAuth(true);
            setToken(res.result.token);
            router.replace("/info");
        } catch (e) {
            Toast.show({
                type: "error",
                text1: e as string,
            });
        }
    };
    const logout = async () => {
        try {
            const token = (await AsyncStorage.getItem("token")) as string;
            await apiLogout(token);
        } catch (e) {
            Toast.show({
                type: "error",
                text1: e as string,
            });
        }
        await AsyncStorage.removeItem("token");
        await AsyncStorage.removeItem("refresh_token");

        setIsAuth(false);
        setToken(null);
        router.replace("/auth");
    };
    const verify = async () => {
        try {
            const token = await AsyncStorage.getItem("token");
            if (token) {
                const res = await apiVerify(token);

                if (res.ok && res.result) {
                    setToken(token);
                    return setIsAuth(true);
                } else {
                    setToken(null);
                    return await logout();
                }
            }
            await logout();
        } catch (e) {
            await logout();
            Toast.show({
                type: "error",
                text1: e as string,
            });
        }
    };

    useEffect(() => {
        const effectWrapper = async () => {
            const token = await AsyncStorage.getItem("token");
            if (token !== null) {
                verify();
            } else {
                setIsAuth(false);
            }
        };
        effectWrapper();
    }, []);

    return { login, logout, verify, setIsAuth, isAuth, token };
};

I tried different storage libs, tried 51 SDK, tried call lib functions in clean project, tried use only in useEffect/useCallback/event handlers/etc. errors doesnt disaper. please help

Share asked Mar 4 at 12:22 Даниил ДуровДаниил Дуров 411 silver badge6 bronze badges 1
  • can you upload here mainLayout code ? – Mahammad Momin Commented Mar 5 at 6:04
Add a comment  | 

1 Answer 1

Reset to default 0

The Error was resolved by updating to 52 SDK and fixing some deps hell. I try CLI deps tools, fix something, restart server and it finaly start working. But now i have problems with reanimated lib, but that is another story...

本文标签: Android problem with quotreactnativeasyncstorageasyncstoragequotStack Overflow