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
editfunction as props to theEditcomponent inApp - Update the
Editcomponent 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
useLocationhook from thereact-routerlibrary.
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:
.gif)