I'm using Ionic 7 and React 18. I want to build a drop down component such that when an option is selected, my URL will change to include the ID of the selected option. I have this set up in my App.tsx file,
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonButton>
<IonIcon icon={logoReact} />
</IonButton>
</IonButtons>
<IonTitle>My Title</IonTitle>
<IonButtons slot="end">
<IonButton>
<IonIcon icon={search} />
</IonButton>
<IonButton>
<IonIcon icon={personCircle} />
</IonButton>
</IonButtons>
</IonToolbar>
<IonToolbar>
<CategorySelectComponent />
</IonToolbar>
</IonHeader>
...
<IonReactRouter>
<IonRouterOutlet>
<Route exact path="/home">
<Home />
</Route>
<Route exact path="/">
<Redirect to="/home" />
</Route>
<Route exact path="/cards/:categoryId">
<CardSlideComponent />
</Route>
</IonRouterOutlet>
and my selection component is as such
import {
IonContent,
IonItem,
IonLabel,
IonPage,
IonSelect,
IonSelectOption,
} from "@ionic/react";
import React, { useEffect } from "react";
import { useState } from "react";
import axios from "axios";
import CardService from "../services/CardService";
import { useHistory } from "react-router-dom";
const CategorySelectComponent: React.FC = () => {
const [selectedValue, setSelectedValue] = useState<string | undefined>(
undefined
);
const [options, setOptions] = useState<Category[]>([]);
const history = useHistory();
console.log(history); // this is always undefined
const handleSelectionChange = (event: CustomEvent) => {
const selectedCategoryId = event.detail.value;
setSelectedValue(selectedCategoryId);
// Navigate to the selected category page
console.log("handle change ...");
console.log(history);
history.push(`/cards/${selectedCategoryId}`);
};
useEffect(() => {
CardService.getCategories(setOptions);
}, []); // Empty dependency array means this effect runs once on component mount
return (
<IonPage>
<IonContent>
<IonItem>
<IonLabel>Choose an option:</IonLabel>
<IonSelect
value={selectedValue}
onIonChange={handleSelectionChange}
interface="popover"
>
{options.map((category) => (
<IonSelectOption key={category.id} value={category.id}>
{category.name}
</IonSelectOption>
))}
</IonSelect>
</IonItem>
<IonItem>
<IonLabel>Selected Value:</IonLabel>
<IonLabel>{selectedValue}</IonLabel>
</IonItem>
</IonContent>
</IonPage>
);
but the "history" component is consistently "undefined". Is there a more "ionic" way of doing this that doesn't involve the history object?
I ran into this same issue recently when needing to use the useIonRouter
hook to check if back navigations were possible. You just need to promote the router component (that provides the routing context, e.g. the history
object) higher in the ReactTree than any component consuming it.
Tuck the IonHeader
component inside the IonReactRouter
component so that CategorySelectComponent
is rendered within its routing context.
<IonReactRouter>
...
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonButton>
<IonIcon icon={logoReact} />
</IonButton>
</IonButtons>
<IonTitle>My Title</IonTitle>
<IonButtons slot="end">
<IonButton>
<IonIcon icon={search} />
</IonButton>
<IonButton>
<IonIcon icon={personCircle} />
</IonButton>
</IonButtons>
</IonToolbar>
<IonToolbar>
<CategorySelectComponent />
</IonToolbar>
</IonHeader>
...
<IonRouterOutlet>
<Route exact path="/home">
<Home />
</Route>
<Route exact path="/">
<Redirect to="/home" />
</Route>
<Route exact path="/cards/:categoryId">
<CardSlideComponent />
</Route>
</IonRouterOutlet>
</IonReactRouter>