Step 19: Navigation

Let’s update the code so when navigate to Edit view we click on edit icon or “add note” button. (We will reuse the same page for adding/editing notes.) Moreover, we should return to the homepage when we click on the “cancel” or “save” buttons in the “edit” page.

pages/Edit.jsx
import { Button, Container, Group, Stack } from "@mantine/core"; import { TextInput, Textarea } from "@mantine/core"; import { useState } from "react"; + import { useNavigate } from "react-router-dom"; function Edit() { const [title, setTitle] = useState(""); const [text, setText] = useState(""); + const navigate = useNavigate(); const handleTitleChange = (event) => { setTitle(event.target.value); }; const handleTextChange = (event) => { setText(event.target.value); }; const handleSave = () => { console.log({ title, text }); + navigate("/", { replace: true }); }; const handleCancel = () => { console.log("cancel"); + navigate("/", { replace: true }); }; return ( <Container> <Stack spacing="lg"> <TextInput placeholder="Your note's title" label="Title" withAsterisk value={title} onChange={handleTitleChange} /> <Textarea placeholder="Your note's text" label="Text" withAsterisk autosize minRows={5} value={text} onChange={handleTextChange} /> <Group position="center" spacing="xl" grow> <Button variant="subtle" onClick={handleCancel}> Cancel </Button> <Button variant="default" onClick={handleSave}> Save </Button> </Group> </Stack> </Container> ); } export default Edit;
components/Header.jsx
import { IconNote } from "@tabler/icons"; import { Grid, Button } from "@mantine/core"; import Search from "./Search"; import PropTypes from "prop-types"; + import { useNavigate } from "react-router-dom"; function Header(props) { const { query, setQuery, add } = props; + const navigate = useNavigate(); const handleOnClick = () => { add(); + navigate("/edit"); }; return ( <Grid> <Grid.Col span={10}> <Search query={query} setQuery={setQuery} /> </Grid.Col> <Grid.Col span={2}> <Button onClick={handleOnClick} fullWidth variant="default" leftIcon={<IconNote />} > Add Note </Button> </Grid.Col> </Grid> ); } export default Header; Header.propTypes = { query: PropTypes.string, setQuery: PropTypes.func, add: PropTypes.func, };
components/NoteControl.jsx
import PropTypes from "prop-types"; import { Accordion, ActionIcon, Box } from "@mantine/core"; import { IconTrashX, IconPencil } from "@tabler/icons"; + import { useNavigate } from "react-router-dom"; function NoteControl(props) { const { note, remove } = props; const { id, title } = note; + const navigate = useNavigate(); const handleOnEdit = () => { + navigate("/edit"); }; const handleOnRemove = () => { remove(id); }; return ( <Box sx={{ display: "flex", alignItems: "center" }}> <Accordion.Control>{title}</Accordion.Control> <ActionIcon onClick={handleOnEdit} size="lg"> <IconPencil size={16} /> </ActionIcon> <ActionIcon onClick={handleOnRemove} size="lg"> <IconTrashX size={16} /> </ActionIcon> </Box> ); } export default NoteControl; NoteControl.propTypes = { remove: PropTypes.func.isRequired, note: PropTypes.shape({ title: PropTypes.string.isRequired, text: PropTypes.string.isRequired, }), };

Notice in all the these cases, we used the useNavigate hook for navigation.

The useNavigate hook returns a function that lets you navigate programmatically.

Observe the app’s behaviour in the browser!