From 256cad70d3fd4500b1abcfea66f3ee622fb90874 Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Fri, 15 Oct 2021 10:19:30 -0700 Subject: [PATCH] Remove useBlocker, usePrompt, and Prompt This commit removes anything to do with blocking. The behavior isn't solid yet in the current release, and we don't want it to block shipping v6 stable. Will revisit post v6 stable. --- docs/api.md | 147 ------------------ docs/guides/index.md | 1 - docs/guides/user-flows/forms-and-prompts.md | 8 - .../__tests__/link-push-test.tsx | 5 +- packages/react-router-dom/index.tsx | 34 ---- packages/react-router-dom/server.tsx | 6 - packages/react-router-native/index.tsx | 41 ----- .../__tests__/navigate-push-test.tsx | 5 +- packages/react-router/index.tsx | 44 +----- 9 files changed, 4 insertions(+), 287 deletions(-) delete mode 100644 docs/guides/user-flows/forms-and-prompts.md diff --git a/docs/api.md b/docs/api.md index 417d4b9627..74575b1528 100644 --- a/docs/api.md +++ b/docs/api.md @@ -63,13 +63,6 @@ There are a few low-level APIs that we use internally that may also prove useful - [`useLinkPressHandler`](#uselinkpresshandler) - returns an event handler to for navigation when building a custom `` in `react-router-native` - [`resolvePath`](#resolvepath) - resolves a relative path against a given URL pathname -### Confirming Navigation - -Sometimes you need to confirm navigation before it actually happens. For example, if the user has entered some data into a form on the current page, you may want to prompt them to save the data before they navigate to a different page. - -- [`usePrompt`](#useprompt) and [``](#prompt) trigger a platform-native confirmation prompt when the user tries to navigate away from the current page -- [`useBlocker`](#useblocker) is a low-level interface that lets you keep the user on the same page and execute a function that will be called when they try to navigate away - ### Search Parameters Access to the URL [search parameters](https://developer.mozilla.org/en-US/docs/Web/API/URL/searchParams) is provided via [the `useSearchParams` hook](#usesearchparams). @@ -514,60 +507,6 @@ function App() { } ``` -### `` - -> **Note:** -> -> This is the web version of ``. For the React Native version, -> [go here](#prompt-native). - -
- Type declaration - -```tsx -declare function Prompt(props: PromptProps): null; - -interface PromptProps { - message: string; - when?: boolean; -} -``` - -
- -A `` is the declarative version of [`usePrompt`](#useprompt). It doesn't render anything. It just calls `usePrompt` with its props. - -> **Note:** -> -> Having a component-based version of the `usePrompt` hook makes it easier to -> use this feature in a [`React.Component`](https://reactjs.org/docs/react-component.html) -> subclass where hooks are not able to be used. - - - -### `` (React Native) - -> **Note:** -> -> This is the React Native version of ``. For the web version, -> [go here](#prompt). - -
- Type declaration - -```tsx -declare function Prompt(props: PromptProps): null; - -interface PromptProps { - message: string; - when?: boolean; -} -``` - -
- -A `` is the declarative version of [`usePrompt`](#useprompt). It doesn't render anything. It just calls `usePrompt` with its props. - ### ``
@@ -869,23 +808,6 @@ interface Path { The [`useResolvedPath` hook](#useresolvedpath) uses `resolvePath` internally to resolve the pathname. If `to` contains a pathname, it is resolved against the current route pathname. Otherwise, it is resolved against the current URL (`location.pathname`). -### `useBlocker` - -
- Type declaration - -```tsx -declare function useBlocker(blocker: Blocker, when?: boolean): void; - -interface Blocker { - (tx: Transition): void; -} -``` - -
- -`useBlocker` is a low-level hook that allows you to block navigation away from the current page, i.e. prevent the current location from changing. This is probably something you don't ever want to do unless you also display a confirmation dialog to the user to help them understand why their navigation attempt was blocked. In these cases, you probably want to use [`usePrompt`](#useprompt) or [``](#prompt) instead. - ### `useHref`
@@ -1148,75 +1070,6 @@ function App() { } ``` -### `usePrompt` - -> **Note:** -> -> This is the web version of `usePrompt`. For the React Native version, -> [go here](#useprompt-native). - -
- Type declaration - -```tsx -declare function usePrompt(message: string, when?: boolean): void; -``` - -
- -The `usePrompt` hook may be used to confirm navigation before the user navigates away from the current page. This is useful when someone has entered unsaved data into a form, and you'd like to prompt them before they accidentally leave or close the tab and lose their work. - -```tsx -import React from "react"; -import { usePrompt } from "react-router-dom"; - -function SignupForm() { - let [formData, setFormData] = React.useState(null); - usePrompt("Are you sure you want to leave?", formData != null); - // ... -} -``` - -`usePrompt` uses [`window.confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) on the web and [the `Alert` module](https://reactnative.dev/docs/alert) on React Native to display native, accessible confirm dialogs. - -> **Note:** -> -> If you need a more custom dialog box, you will have to use [`useBlocker`](#useblocker) -> directly and handle accessibility issues yourself. - - - -### `usePrompt` (React Native) - -> **Note:** -> -> This is the React Native version of `usePrompt`. For the web version, -> [go here](#useprompt). - -
- Type declaration - -```tsx -declare function usePrompt(message: string, when?: boolean): void; -``` - -
- -The `usePrompt` hook may be used to confirm navigation before the user navigates away from the current page. This is useful when someone has entered unsaved data into a form, and you'd like to prompt them before they accidentally leave or close the tab and lose their work. - -```tsx -import React from "react"; -import { usePrompt } from "react-router-native"; - -function SignupForm() { - let [formData, setFormData] = React.useState(null); - usePrompt("Are you sure you want to leave?", formData != null); - // ... -} -``` - -The React Native version of `usePrompt` calls the `alert` method from the [React Native Alert class](https://reactnative.dev/docs/alert). - ### `useResolvedPath`
diff --git a/docs/guides/index.md b/docs/guides/index.md index c7a5b24f84..0d07e9002f 100644 --- a/docs/guides/index.md +++ b/docs/guides/index.md @@ -18,7 +18,6 @@ build a certain capability or feature of your app with React Router. ## Common User Flows - [Login and Authentication](user-flows/login-and-auth.md) -- [Forms and Prompts](user-flows/forms-and-prompts.md) - [Transitions and Animation](user-flows/transitions-and-animation.md) - [Passing Data Between Routes Using `location.state`](user-flows/passing-data.md) - [Persisting Data Using `location.key`](user-flows/persisting-data.md) diff --git a/docs/guides/user-flows/forms-and-prompts.md b/docs/guides/user-flows/forms-and-prompts.md deleted file mode 100644 index 4eaa8e88c8..0000000000 --- a/docs/guides/user-flows/forms-and-prompts.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Forms and Prompts -order: 2 ---- - -# Forms and Prompts - -TODO diff --git a/packages/react-router-dom/__tests__/link-push-test.tsx b/packages/react-router-dom/__tests__/link-push-test.tsx index 1168631be9..2437d62909 100644 --- a/packages/react-router-dom/__tests__/link-push-test.tsx +++ b/packages/react-router-dom/__tests__/link-push-test.tsx @@ -32,11 +32,8 @@ function createMockHistory({ pathname = "/", search = "", hash = "" }) { forward() {}, listen() { return () => {}; - }, - block() { - return () => {}; } - } as History; + } as Omit; } describe("Link push and replace", () => { diff --git a/packages/react-router-dom/index.tsx b/packages/react-router-dom/index.tsx index 4952cc1455..3aa790785e 100644 --- a/packages/react-router-dom/index.tsx +++ b/packages/react-router-dom/index.tsx @@ -13,7 +13,6 @@ import { matchPath, resolvePath, renderMatches, - useBlocker, useHref, useInRouterContext, useLocation, @@ -61,7 +60,6 @@ export { matchPath, renderMatches, resolvePath, - useBlocker, useHref, useInRouterContext, useLocation, @@ -313,23 +311,6 @@ if (__DEV__) { NavLink.displayName = "NavLink"; } -export interface PromptProps { - message: string; - when?: boolean; -} - -/** - * A declarative interface for showing a window.confirm dialog with the given - * message when the user tries to navigate away from the current page. - * - * This also serves as a reference implementation for anyone who wants to - * create their own custom prompt component. - */ -export function Prompt({ message, when }: PromptProps) { - usePrompt(message, when); - return null; -} - //////////////////////////////////////////////////////////////////////////////// // HOOKS //////////////////////////////////////////////////////////////////////////////// @@ -379,21 +360,6 @@ export function useLinkClickHandler< ); } -/** - * Prevents navigation away from the current page using a window.confirm prompt - * with the given message. - */ -export function usePrompt(message: string, when = true) { - let blocker = React.useCallback( - tx => { - if (window.confirm(message)) tx.retry(); - }, - [message] - ); - - useBlocker(blocker, when); -} - /** * A convenient wrapper for reading and writing search parameters via the * URLSearchParams interface. diff --git a/packages/react-router-dom/server.tsx b/packages/react-router-dom/server.tsx index 2f3c59fcf1..6054250c38 100644 --- a/packages/react-router-dom/server.tsx +++ b/packages/react-router-dom/server.tsx @@ -67,12 +67,6 @@ export function StaticRouter({ `You cannot use navigator.forward() on the server because it is a stateless ` + `environment.` ); - }, - block() { - throw new Error( - `You cannot use navigator.block() on the server because it is a stateless ` + - `environment.` - ); } }; diff --git a/packages/react-router-native/index.tsx b/packages/react-router-native/index.tsx index ff9badee45..a679ada813 100644 --- a/packages/react-router-native/index.tsx +++ b/packages/react-router-native/index.tsx @@ -22,7 +22,6 @@ import { matchPath, resolvePath, renderMatches, - useBlocker, useHref, useInRouterContext, useLocation, @@ -54,7 +53,6 @@ export { matchPath, resolvePath, renderMatches, - useBlocker, useHref, useInRouterContext, useLocation, @@ -147,23 +145,6 @@ export function Link({ return ; } -export interface PromptProps { - message: string; - when?: boolean; -} - -/** - * A declarative interface for showing an Alert dialog with the given - * message when the user tries to navigate away from the current screen. - * - * This also serves as a reference implementation for anyone who wants - * to create their own custom prompt component. - */ -export function Prompt({ message, when }: PromptProps) { - usePrompt(message, when); - return null; -} - //////////////////////////////////////////////////////////////////////////////// // HOOKS //////////////////////////////////////////////////////////////////////////////// @@ -264,28 +245,6 @@ function trimScheme(url: string) { return url.replace(/^.*?:\/\//, ""); } -/** - * Prompts the user with an Alert before they leave the current screen. - */ -export function usePrompt(message: string, when = true) { - let blocker = React.useCallback( - tx => { - Alert.alert("Confirm", message, [ - { text: "Cancel", onPress() {} }, - { - text: "OK", - onPress() { - tx.retry(); - } - } - ]); - }, - [message] - ); - - useBlocker(blocker, when); -} - /** * A convenient wrapper for accessing individual query parameters via the * URLSearchParams interface. diff --git a/packages/react-router/__tests__/navigate-push-test.tsx b/packages/react-router/__tests__/navigate-push-test.tsx index 9bc53dbd7b..0eba8b962b 100644 --- a/packages/react-router/__tests__/navigate-push-test.tsx +++ b/packages/react-router/__tests__/navigate-push-test.tsx @@ -18,11 +18,8 @@ function createMockHistory(initialLocation: Partial) { forward() {}, listen() { return () => {}; - }, - block() { - return () => {}; } - } as History; + } as Omit; } describe("navigate", () => { diff --git a/packages/react-router/index.tsx b/packages/react-router/index.tsx index 36a12c4aa1..4c38b2317f 100644 --- a/packages/react-router/index.tsx +++ b/packages/react-router/index.tsx @@ -1,15 +1,13 @@ import * as React from "react"; import { Action, createMemoryHistory, parsePath } from "history"; import type { - Blocker, History, InitialEntry, Location, MemoryHistory, Path, State, - To, - Transition + To } from "history"; function invariant(cond: any, message: string): asserts cond { @@ -56,7 +54,7 @@ function warningOnce(key: string, cond: boolean, message: string) { */ export type Navigator = Omit< History, - "action" | "location" | "back" | "forward" | "listen" + "action" | "location" | "back" | "forward" | "listen" | "block" >; interface NavigationContextObject { @@ -341,44 +339,6 @@ export function Routes({ // HOOKS /////////////////////////////////////////////////////////////////////////////// -/** - * Blocks all navigation attempts. This is useful for preventing the page from - * changing until some condition is met, like saving form data. - * - * @see https://reactrouter.com/api/useBlocker - */ -export function useBlocker(blocker: Blocker, when = true): void { - invariant( - useInRouterContext(), - // TODO: This error is probably because they somehow have 2 versions of the - // router loaded. We can help them understand how to avoid that. - `useBlocker() may be used only in the context of a component.` - ); - - let { navigator } = React.useContext(NavigationContext); - - React.useEffect(() => { - if (!when) return; - - let unblock = navigator.block((tx: Transition) => { - let autoUnblockingTx = { - ...tx, - retry() { - // Automatically unblock the transition so it can play all the way - // through before retrying it. TODO: Figure out how to re-enable - // this block if the transition is cancelled for some reason. - unblock(); - tx.retry(); - } - }; - - blocker(autoUnblockingTx); - }); - - return unblock; - }, [navigator, blocker, when]); -} - /** * Returns the full href for the given "to" value. This is useful for building * custom links that are also accessible and preserve right-click behavior.