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
1 Answer
Reset to default 0The 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...