'React onClick routing ONLY works SOMETIMES
Here is the video proof. https://dsc.cloud/leonardchoo/Screen-Recording-2022-03-08-at-17.25.58.mov
I'm running into a mysterious error where I click the button for navigation, "onClick" event is fired but it does not redirect and render the target component.
As you can see in the screenshot, the onClick event is logged, but the redirect does not happen.
I reproduced the situation here in CodeSandbox.
Stack
- React TS
- Mantine UI
- React Router V5
How can I solve this issue?
Solution 1:[1]
First thing I noticed in your code was that is is rendering a WrapperPage component around each routed component with the navigation logic. I tried simplifying the WrapperPage code as much as possible.
Steps Taken:
- Refactored the
headerandnavbarprops into standalone components in case there was issue generating JSX - Wrapped the
Switchcomponent inAppwith a singleWrapperPageinstead of each routed component
The issue persisted.
I next removed the UnstyledButton from @mantine/core so only the Link components were rendered, and could not reproduce. I then tried vanilla HTML buttons instead of the UnstyledButton and they again reproduced the issue.
So it seems it is an issue with rendering an interactive element (i.e. anchor tag from Link) within another interactive element (i.e. button from UnstyledButton) that is an issue. Swapping the element order, i.e. Link wrapping the UnstyledButton, appears to reduce the issue. I can't seem to reproduce the issue with the DOM structured this way.
Header
const CustomHeader = ({
opened,
setOpened
}: {
opened: boolean;
setOpened: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const theme = useMantineTheme();
return (
<Header height={70} padding="md">
{/* Handle other responsive styles with MediaQuery component or createStyles function */}
<div style={{ display: "flex", alignItems: "center", height: "100%" }}>
<MediaQuery largerThan="sm" styles={{ display: "none" }}>
<Burger
opened={opened}
onClick={() => setOpened((o) => !o)}
size="sm"
color={theme.colors.gray[6]}
mr="xl"
/>
</MediaQuery>
<Group>
<ThemeIcon variant="light" color="orange">
?
</ThemeIcon>
<Text>Mantine AppShell with React Router</Text>
</Group>
</div>
</Header>
);
};
Navbar
const CustomNavbar = ({ opened }: { opened: boolean }) => {
const location = useLocation();
const { classes } = useStyles();
return (
<Navbar
padding="md"
// Breakpoint at which navbar will be hidden if hidden prop is true
hiddenBreakpoint="sm"
// Hides navbar when viewport size is less than value specified in hiddenBreakpoint
hidden={!opened}
// when viewport size is less than theme.breakpoints.sm navbar width is 100%
// viewport size > theme.breakpoints.sm – width is 300px
// viewport size > theme.breakpoints.lg – width is 400px
width={{ sm: 300, lg: 400 }}
>
<Link
to="/dashboard"
className={classes.link}
>
<UnstyledButton
className={
location.pathname === "/dashboard"
? classes.button_active
: classes.button
}
>
<Group>
<ThemeIcon variant="light">
<DashboardIcon />
</ThemeIcon>
<Text size="sm">Dashboard</Text>
</Group>
</UnstyledButton>
</Link>
<Link
to="/new-recording"
className={classes.link}
>
<UnstyledButton
className={
location.pathname === "/new-recording"
? classes.button_active
: classes.button
}
>
<Group>
<ThemeIcon variant="light" color="red">
<RadiobuttonIcon />
</ThemeIcon>
<Text size="sm">New Recording</Text>
</Group>
</UnstyledButton>
</Link>
<Link
to="/calendar"
className={classes.link}
>
<UnstyledButton
className={
location.pathname === "/calendar"
? classes.button_active
: classes.button
}
>
<Group>
<ThemeIcon variant="light" color="orange">
<CalendarIcon />
</ThemeIcon>
<Text size="sm">Calendar</Text>
</Group>
</UnstyledButton>
</Link>
</Navbar>
);
};
WrapperPage
const WrapperPage = ({ children }: Props): JSX.Element => {
const [opened, setOpened] = useState(false);
return (
<AppShell
// navbarOffsetBreakpoint controls when navbar should no longer be offset with padding-left
navbarOffsetBreakpoint="sm"
// fixed prop on AppShell will be automatically added to Header and Navbar
fixed
header={<CustomHeader opened={opened} setOpened={setOpened} />}
navbar={<CustomNavbar opened={opened} />}
>
{children}
</AppShell>
);
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Drew Reese |

