From 2cb3f75f022be4bffd41f523291b007f26ca4dbe Mon Sep 17 00:00:00 2001 From: Mark Lawlor Date: Thu, 22 Jun 2023 08:49:38 +1000 Subject: [PATCH 1/2] feat: deprecate redirect prop --- packages/expo-router/src/hooks.ts | 3 +- packages/expo-router/src/useDeprecated.ts | 35 +++++++++++++++++++++++ packages/expo-router/src/views/Screen.tsx | 6 ++++ packages/expo-router/src/views/Splash.tsx | 11 ++++--- 4 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 packages/expo-router/src/useDeprecated.ts diff --git a/packages/expo-router/src/hooks.ts b/packages/expo-router/src/hooks.ts index 96758a5d5..3aa0ca948 100644 --- a/packages/expo-router/src/hooks.ts +++ b/packages/expo-router/src/hooks.ts @@ -11,6 +11,7 @@ import { useStoreRouteInfo, } from "./global-state/router-store"; import { Router } from "./types"; +import { useDeprecated } from "./useDeprecated"; type SearchParams = Record; @@ -28,7 +29,7 @@ export function useRootNavigation() { // Wraps useLinkTo to provide an API which is similar to the Link component. export function useLink() { - console.warn("`useLink()` is deprecated in favor of `useRouter()`"); + useDeprecated("`useLink()` is deprecated in favor of `useRouter()`"); return useRouter(); } diff --git a/packages/expo-router/src/useDeprecated.ts b/packages/expo-router/src/useDeprecated.ts new file mode 100644 index 000000000..20e63bc47 --- /dev/null +++ b/packages/expo-router/src/useDeprecated.ts @@ -0,0 +1,35 @@ +import { useLayoutEffect } from "react"; +import { Platform } from "react-native"; + +// Node environment may render in multiple processes causing the warning to log mutiple times +// Hence we skip the warning in these environments. +const canWarn = Platform.select({ + native: process.env.NODE_ENV !== "production", + default: + process.env.NODE_ENV !== "production" && typeof window !== "undefined", +}); + +const warned = new Set(); + +export function useWarnOnce( + message: string, + guard: unknown = true, + key = message +) { + // useLayoutEffect typically doesn't run in node environments. + // Combined with skipWarn, this should prevent unwanted warnings + useLayoutEffect(() => { + if (guard && canWarn && !warned.has(key)) { + warned.add(key); + console.warn(message); + } + }, [guard]); +} + +export function useDeprecated( + message: string, + guard: unknown = true, + key = message +) { + return useWarnOnce(key, guard, `Expo Router: ${message}`); +} diff --git a/packages/expo-router/src/views/Screen.tsx b/packages/expo-router/src/views/Screen.tsx index 6771a947a..4da275239 100644 --- a/packages/expo-router/src/views/Screen.tsx +++ b/packages/expo-router/src/views/Screen.tsx @@ -1,5 +1,6 @@ import React from "react"; +import { useDeprecated } from "../useDeprecated"; import { useNavigation } from "../useNavigation"; export type ScreenProps< @@ -36,6 +37,11 @@ export function Screen({ navigation.setOptions(options ?? {}); }, [navigation, options]); + useDeprecated( + "The `redirect` prop on is deprecated and will be removed. Please use `router.redirect` instead", + redirect + ); + if (process.env.NODE_ENV !== "production") { // eslint-disable-next-line react-hooks/rules-of-hooks React.useEffect(() => { diff --git a/packages/expo-router/src/views/Splash.tsx b/packages/expo-router/src/views/Splash.tsx index adb5fe313..8a07e1985 100644 --- a/packages/expo-router/src/views/Splash.tsx +++ b/packages/expo-router/src/views/Splash.tsx @@ -1,7 +1,8 @@ import * as SplashModule from "expo-splash-screen"; import { nanoid } from "nanoid/non-secure"; import * as React from "react"; -import { Platform } from "react-native"; + +import { useDeprecated } from "../useDeprecated"; const globalStack: string[] = []; @@ -25,11 +26,9 @@ const globalStack: string[] = []; */ export function SplashScreen() { useGlobalSplash(); - React.useEffect(() => { - console.warn( - "The component is deprecated. Use `SplashScreen.preventAutoHideAsync()` and `SplashScreen.hideAsync` from `expo-router` instead." - ); - }, []); + useDeprecated( + "The component is deprecated. Use `SplashScreen.preventAutoHideAsync()` and `SplashScreen.hideAsync` from `expo-router` instead." + ); return null; } From 9df85c7bf917ff3b62b011d983c94586c012b347 Mon Sep 17 00:00:00 2001 From: Mark Lawlor Date: Mon, 26 Jun 2023 10:04:08 +1000 Subject: [PATCH 2/2] feat: tree shake useDeprecated hook. fix missing import --- packages/expo-router/src/views/Screen.tsx | 11 +++++++---- packages/expo-router/src/views/Splash.tsx | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/expo-router/src/views/Screen.tsx b/packages/expo-router/src/views/Screen.tsx index 4da275239..179583053 100644 --- a/packages/expo-router/src/views/Screen.tsx +++ b/packages/expo-router/src/views/Screen.tsx @@ -37,10 +37,13 @@ export function Screen({ navigation.setOptions(options ?? {}); }, [navigation, options]); - useDeprecated( - "The `redirect` prop on is deprecated and will be removed. Please use `router.redirect` instead", - redirect - ); + if (process.env.NODE_ENV === "development") { + // eslint-disable-next-line react-hooks/rules-of-hooks + useDeprecated( + "The `redirect` prop on is deprecated and will be removed. Please use `router.redirect` instead", + redirect + ); + } if (process.env.NODE_ENV !== "production") { // eslint-disable-next-line react-hooks/rules-of-hooks diff --git a/packages/expo-router/src/views/Splash.tsx b/packages/expo-router/src/views/Splash.tsx index 8a07e1985..808a973b2 100644 --- a/packages/expo-router/src/views/Splash.tsx +++ b/packages/expo-router/src/views/Splash.tsx @@ -1,6 +1,7 @@ import * as SplashModule from "expo-splash-screen"; import { nanoid } from "nanoid/non-secure"; import * as React from "react"; +import { Platform } from "react-native"; import { useDeprecated } from "../useDeprecated";