diff --git a/BREAKING.md b/BREAKING.md index c415111564..a05c967582 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -66,12 +66,62 @@ Routes that contain nested routes or child `IonRouterOutlet` components need a ` Route parameters are now accessed via the `useParams` hook instead of props: ```diff +- import { RouteComponentProps } from 'react-router-dom'; ++ import { useParams } from 'react-router-dom'; + - const MyComponent: React.FC> = ({ match }) => { - const id = match.params.id; + const MyComponent: React.FC = () => { + const { id } = useParams<{ id: string }>(); ``` +**RouteComponentProps Removed** + +The `RouteComponentProps` type and its `history`, `location`, and `match` props are no longer available in React Router v6. Use the equivalent hooks instead: + +- `history` -> `useNavigate` (see below) or `useIonRouter` +- `match.params` -> `useParams` (covered above) +- `location` -> `useLocation` + +```diff +- import { RouteComponentProps } from 'react-router-dom'; ++ import { useNavigate, useLocation } from 'react-router-dom'; ++ import { useIonRouter } from '@ionic/react'; + +- const MyComponent: React.FC = ({ history, location }) => { +- history.push('/path'); +- history.replace('/path'); +- history.goBack(); +- console.log(location.pathname); ++ const MyComponent: React.FC = () => { ++ const navigate = useNavigate(); ++ const router = useIonRouter(); ++ const location = useLocation(); ++ // In an event handler or useEffect: ++ navigate('/path'); ++ navigate('/path', { replace: true }); ++ router.goBack(); ++ console.log(location.pathname); +``` + +**Exact Prop Removed** + +The `exact` prop is no longer needed. React Router v6 routes match exactly by default. To match sub-paths, use a `/*` suffix on the path: + +```diff +- ++ +``` + +**Render Prop Removed** + +The `render` prop has been replaced with the `element` prop: + +```diff +- } /> ++ } /> +``` + **Programmatic Navigation** The `useHistory` hook has been replaced with `useNavigate`: @@ -79,18 +129,71 @@ The `useHistory` hook has been replaced with `useNavigate`: ```diff - import { useHistory } from 'react-router-dom'; + import { useNavigate } from 'react-router-dom'; ++ import { useIonRouter } from '@ionic/react'; - const history = useHistory(); + const navigate = useNavigate(); ++ const router = useIonRouter(); -- history.goBack(); -+ navigate(-1); +- history.push('/path'); ++ navigate('/path'); - history.replace('/path'); + navigate('/path', { replace: true }); -- history.push('/path'); -+ navigate('/path'); +- history.goBack(); ++ router.goBack(); ``` -For more information on migrating from React Router v5 to v6, refer to the [React Router v6 Upgrade Guide](https://reactrouter.com/en/main/upgrading/v5). +**Custom History Prop Removed** + +The `history` prop has been removed from `IonReactRouter`, `IonReactHashRouter`, and `IonReactMemoryRouter`. React Router v6's `BrowserRouter`, `HashRouter`, and `MemoryRouter` no longer accept custom `history` objects. + +```diff +- import { createBrowserHistory } from 'history'; +- const history = createBrowserHistory(); +- ++ +``` + +For `IonReactMemoryRouter` (commonly used in tests), use `initialEntries` instead: + +```diff +- import { createMemoryHistory } from 'history'; +- const history = createMemoryHistory({ initialEntries: ['/start'] }); +- ++ +``` + +**IonRedirect Removed** + +The `IonRedirect` component has been removed. Use React Router's `` component instead: + +```diff +- import { IonRedirect } from '@ionic/react'; +- ++ import { Navigate } from 'react-router-dom'; ++ } /> +``` + +**Path Regex Constraints Removed** + +React Router v6 no longer supports regex constraints in path parameters (e.g., `/:tab(sessions)`). Use literal paths instead: + +```diff +- +- ++ } /> ++ } /> +``` + +**IonRoute API Changes** + +The `IonRoute` component follows the same API changes as React Router's ``. The `render` prop has been replaced with `element`, and the `exact` prop has been removed: + +```diff +- } /> ++ } /> +``` + +For more information on migrating from React Router v5 to v6, refer to the [React Router v6 Upgrade Guide](https://reactrouter.com/6.28.0/upgrading/v5). diff --git a/packages/react-router/src/ReactRouter/IonRouter.tsx b/packages/react-router/src/ReactRouter/IonRouter.tsx index 83c2516ecf..95443d3f7c 100644 --- a/packages/react-router/src/ReactRouter/IonRouter.tsx +++ b/packages/react-router/src/ReactRouter/IonRouter.tsx @@ -138,7 +138,7 @@ export const IonRouter = ({ children, registerHistoryListener }: PropsWithChildr let leavingLocationInfo: RouteInfo; /** * A programmatic navigation was triggered. - * e.g., ``, `history.push()`, or `handleNavigate()` + * e.g., ``, `navigate()`, or `handleNavigate()` */ if (incomingRouteParams.current) { /** @@ -176,7 +176,7 @@ export const IonRouter = ({ children, registerHistoryListener }: PropsWithChildr /** * A `REPLACE` action can be triggered by React Router's - * `` component. + * `` component. */ if (action === 'REPLACE') { incomingRouteParams.current = { @@ -280,7 +280,7 @@ export const IonRouter = ({ children, registerHistoryListener }: PropsWithChildr } else { routeInfo.pushedByRoute = lastRoute?.pushedByRoute ?? leavingLocationInfo.pathname; } - // Triggered by `history.replace()` or a `` component, etc. + // Triggered by `navigate()` with replace or a `` component, etc. } else if (routeInfo.routeAction === 'replace') { /** * Make sure to set the `lastPathname`, etc.. to the current route @@ -566,7 +566,6 @@ export const IonRouter = ({ children, registerHistoryListener }: PropsWithChildr { - context!: React.ContextType; - - render() { - const IonRedirectInner = this.context.getIonRedirect(); - - if (!this.context.hasIonicRouter() || !IonRedirect) { - console.error( - 'You either do not have an Ionic Router package, or your router does not support using ' - ); - return null; - } - - return ; - } - - static get contextType() { - return NavContext; - } -} diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts index 5355401a79..f96117e94e 100644 --- a/packages/react/src/components/index.ts +++ b/packages/react/src/components/index.ts @@ -124,7 +124,7 @@ export { IonBackButton } from './navigation/IonBackButton'; export { IonRouterOutlet } from './IonRouterOutlet'; export { IonIcon } from './IonIcon'; export * from './IonRoute'; -export * from './IonRedirect'; + export * from './IonRouterContext'; // Utils diff --git a/packages/react/src/contexts/NavContext.ts b/packages/react/src/contexts/NavContext.ts index fd6126960a..fc25a2dec1 100644 --- a/packages/react/src/contexts/NavContext.ts +++ b/packages/react/src/contexts/NavContext.ts @@ -7,8 +7,6 @@ import type { RouteInfo } from '../models'; export interface NavContextState { getIonRoute: () => any; - getIonRedirect: () => any; - getPageManager: () => any; getStackManager: () => any; goBack: (route?: string | RouteInfo, animationBuilder?: AnimationBuilder) => void; navigate: ( @@ -27,9 +25,7 @@ export interface NavContextState { } export const NavContext = /*@__PURE__*/ React.createContext({ - getIonRedirect: () => undefined, getIonRoute: () => undefined, - getPageManager: () => undefined, getStackManager: () => undefined, goBack: (route?: string | RouteInfo) => { if (typeof window !== 'undefined') { diff --git a/packages/react/src/routing/NavManager.tsx b/packages/react/src/routing/NavManager.tsx index 2739694780..f0b686257e 100644 --- a/packages/react/src/routing/NavManager.tsx +++ b/packages/react/src/routing/NavManager.tsx @@ -11,7 +11,6 @@ import type { RouterDirection } from '../models/RouterDirection'; import type { RouterOptions } from '../models/RouterOptions'; import type { LocationHistory } from './LocationHistory'; -import PageManager from './PageManager'; // TODO(FW-2959): types @@ -30,7 +29,6 @@ interface NavManagerProps { onSetCurrentTab: (tab: string, routeInfo: RouteInfo) => void; onChangeTab: (tab: string, path: string, routeOptions?: any) => void; onResetTab: (tab: string, path: string, routeOptions?: any) => void; - ionRedirect: any; ionRoute: any; stackManager: any; locationHistory: LocationHistory; @@ -61,10 +59,8 @@ export class NavManager extends React.PureComponent true, navigate: this.navigate.bind(this), - getIonRedirect: this.getIonRedirect.bind(this), getIonRoute: this.getIonRoute.bind(this), getStackManager: this.getStackManager.bind(this), - getPageManager: this.getPageManager.bind(this), routeInfo: this.props.routeInfo, setCurrentTab: this.props.onSetCurrentTab, changeTab: this.props.onChangeTab, @@ -111,14 +107,6 @@ export class NavManager extends React.PureComponent