Step 20: Edit Notes
Here is what we want:
- When a user clicks on the edit icon, they should be redirected to the edit page.
- The title and text of the note must be displayed in the editor.
- The user should be able to make changes to the title and text.
- When they click on the save button, their changes should be saved and they should be redirected to the homepage.
To implement this behaviour, we start with adding an edit
function to App
as follows:
const edit = (id, title, text) => {
setNotes((notes) =>
notes.map((note) => {
if (note.id !== id) {
return note;
} else {
return { id, title, text };
}
})
);
};
- Pass the
edit
function as props to theEdit
component inApp
- Update the
Edit
component PropTypes specification to account for this addition.
When we navigate (redirect the user) to the edit page, we should pass the note attributes (the one to be edited). We can do this through useNavigation
hook as follows. Make the following change to the components/NoteControl.jsx
:
const handleOnEdit = () => {
- navigate("/edit");
+ navigate("/edit", { state: { id, title, text } });
};
Notice how I send the “state” through navigation. This “state” is not the same as a React component state. This “state” belongs to the browser history API (see History.state). The state
object can be anything that can be serialized (so you cannot pass functions to it, only data).
In order to retrieve the history state, we need to employ the
useLocation
hook from thereact-router
library.
Update the pages/Edit.jsx
as follows:
import { Button, Container, Group, Stack } from "@mantine/core";
import { TextInput, Textarea } from "@mantine/core";
import { useEffect, useState } from "react";
import PropTypes from "prop-types";
import { useNavigate, useLocation } from "react-router-dom";
function Edit(props) {
const { edit } = props;
const navigate = useNavigate();
const location = useLocation();
const { id, text: _text, title: _title, mode } = location.state;
const [title, setTitle] = useState("");
const [text, setText] = useState("");
useEffect(() => {
if (_text !== text) {
setText(_text);
}
if (_title !== title) {
setTitle(_title);
}
}, [_text, _title]);
const handleTitleChange = (event) => {
setTitle(event.target.value);
};
const handleTextChange = (event) => {
setText(event.target.value);
};
const handleSave = () => {
edit(id, 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;
Edit.propTypes = {
edit: PropTypes.func,
};
Notice after retrieving the history state from the location.state
object, I used a useEffect
hook to initialize the title
and text
states.
Observe how the editing feature works now: