Search by

    Terakhir diperbaharui: Jul 1, 2021

    Membuat ulang Aplikasi DinoTes #2

    Setelah berhasil membuat fungsi untuk menambah note baru, pada bagian ini kita akan melanjutkan menambahkan beberapa fungsi lain yaitu:

    • Menampilkan semua note pada halaman utama
    • Mengedit note

    6. Note List Page

    Step by Step

    Buat sebuah file baru bernama NotesList.js di dalam folder components.

    Component NotesList ini akan menjadi component yang berfungsi untuk menampilkan semua note yang sudah ditambahkan.

    Tambahkan code berikut ini:

    components/NotesList

    1import React, { useEffect, useState } from "react";
    2import { API } from "@aws-amplify/api";
    3
    4import { listNotes } from "../graphql/queries";
    5
    6const NotesList = () => {
    7 const [notes, setNotes] = useState("");
    8
    9 useEffect(() => {
    10 async function getNotes() {
    11 const { data } = await API.graphql({
    12 authMode: "API_KEY",
    13 query: listNotes,
    14 });
    15 setNotes(data.listNotes.items);
    16 }
    17
    18 getNotes();
    19 }, []);
    20
    21 return (
    22 <div className="flex flex-col items-center justify-center m-4">
    23 <div className="grid grid-cols-1 md:grid-cols-3 gap-4 my-8 overflow-y-auto">
    24 {notes &&
    25 notes.map((note) => {
    26 return (
    27 <div className="text-left p-4 border rounded-md" key={note.id}>
    28 <h4 className="text-lg font-semibold text-purple-900">
    29 {note.title}
    30 </h4>
    31 <p>{note.content.slice(0, 101)}</p>
    32 </div>
    33 );
    34 })}
    35 </div>
    36 </div>
    37 );
    38};
    39
    40export default NotesList;

    Import NotesList ke file index.js

    pages/index.js

    1import Layout from "../components/Layout";
    2import NotesList from "../components/NotesList";
    3
    4const Home = () => (
    5 <div className="text-center">
    6 <Layout>
    7 <NotesList />
    8 </Layout>
    9 </div>
    10);
    11
    12export default Home;

    Sekarang jika kita akses halaman utama (localhost:3000) kita akan dapatkan data note yang sudah kita submit sebelumnya.

    dinotes noteslist

    7. Edit Page

    Agar note bisa diedit maka kita perlu lakukan langkah-langkah berikut.

    Step by Step

    Buat sebuah file baru bernama EditNoteForm.js di dalam folder components.

    Dan tambahkan code berikut ini:

    1import React, { useState } from "react";
    2import { API } from "@aws-amplify/api";
    3import { useRouter } from "next/router";
    4import { deleteNote, updateNote } from "../graphql/mutations";
    5import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
    6import { faSave, faTrashAlt } from "@fortawesome/free-solid-svg-icons";
    7import { useFormik } from "formik";
    8
    9import Message from "./Message";
    10
    11const InfoWrapper = (props) => {
    12 const { status } = props;
    13
    14 if (status !== null) {
    15 if (status === false) {
    16 return <Message type="error" text="Title cannot be empty" />;
    17 }
    18 return <Message type="success" text="Data successfully saved" />;
    19 }
    20 return <></>;
    21};
    22
    23const EditNoteForm = (props) => {
    24 const [isSuccess, setIsSuccess] = useState(null);
    25 const router = useRouter();
    26
    27 const { note } = props;
    28
    29 const formik = useFormik({
    30 initialValues: {
    31 title: note.title,
    32 content: note.content,
    33 },
    34 onSubmit: async (values) => {
    35 await API.graphql({
    36 authMode: "API_KEY",
    37 query: updateNote,
    38 variables: {
    39 input: { id: note.id, title: values.title, content: values.content },
    40 },
    41 });
    42
    43 setIsSuccess(true);
    44 },
    45 });
    46
    47 const handleDelete = async () => {
    48 await API.graphql({
    49 authMode: "API_KEY",
    50 query: deleteNote,
    51 variables: {
    52 input: { id: note.id },
    53 },
    54 });
    55
    56 router.push("/");
    57 };
    58
    59 return (
    60 <>
    61 <InfoWrapper status={isSuccess} />
    62 <form className="flex flex-col w-4/5" onSubmit={formik.handleSubmit}>
    63 <div className="flex flex-col">
    64 <input
    65 className="my-8 p-2 text-xl font-bold w-full focus:outline-none focus:ring focus:border-blue-300"
    66 type="text"
    67 name="title"
    68 placeholder="Title"
    69 onChange={formik.handleChange}
    70 value={formik.values.title}
    71 ></input>
    72 <textarea
    73 className="resize-y mb-8 p-2 focus:outline-none focus:ring focus:border-blue-300"
    74 name="content"
    75 rows="12"
    76 placeholder="Your content goes here.."
    77 onChange={formik.handleChange}
    78 value={formik.values.content}
    79 ></textarea>
    80 </div>
    81 <div className="flex justify-end">
    82 <button
    83 className="bg-purple-700 text-white text-base m-2 p-3 border rounded-md"
    84 type="submit"
    85 >
    86 <FontAwesomeIcon icon={faSave} /> &nbsp; Save
    87 </button>
    88 <button
    89 className="bg-red-500 text-white text-base m-2 p-3 border rounded-md"
    90 onClick={handleDelete}
    91 >
    92 <FontAwesomeIcon icon={faTrashAlt} /> &nbsp; Delete
    93 </button>
    94 </div>
    95 </form>
    96 </>
    97 );
    98};
    99
    100export default EditNoteForm;

    Cara user mengedit notes tidak berubah, jika user ingin mengedit sebuah note maka user harus klik note tersebut di halaman utama.

    Selanjutnya user akan diarahkan ke halaman edit, dimana aplikasi akan melakukan render component EditNoteForm dengan data sesuai id dari note yang bisa didapatkan dari alamat url.

    Konsep yang digunakan untuk membuat fungsi edit ini adalah Dynamic Routes.

    Pada Next.js, menerapkan konsep ini bisa dibilang sangat mudah. Penjelasan lengkap bisa dilihat kembali pada pembahasan Next.js.

    Dynamic Routes

    Buat sebuah folder dengan nama edit di dalam folder pages, kemudian buat sebuah file dengan nama [id].js.

    dinotes create edit id file

    Tambahkan code berikut ini di dalam file [id].js

    1import React, { useState, useEffect } from "react";
    2import { useRouter } from "next/router";
    3import Link from "next/link";
    4import { API } from "@aws-amplify/api";
    5import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
    6import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
    7import { getNote } from "../../graphql/queries";
    8
    9import Layout from "../../components/Layout";
    10import EditNoteForm from "../../components/EditNoteForm";
    11
    12const EditPage = () => {
    13 const [note, setNote] = useState(null);
    14 const router = useRouter();
    15
    16 const { id } = router.query;
    17
    18 useEffect(() => {
    19 async function getSingleNote() {
    20 const { data } = await API.graphql({
    21 authMode: "API_KEY",
    22 query: getNote,
    23 variables: { id: id },
    24 });
    25
    26 setNote(data.getNote);
    27 }
    28
    29 getSingleNote();
    30 }, []);
    31
    32 if (!note) return null;
    33
    34 return (
    35 <Layout>
    36 <div className="flex flex-col items-center justify-center m-4">
    37 <div className="flex w-full">
    38 <div className="text-lg font-semibold text-blue-500">
    39 <FontAwesomeIcon icon={faArrowLeft} /> &nbsp;{" "}
    40 <Link href="/">Back</Link>
    41 </div>
    42 </div>
    43 <EditNoteForm note={note} />
    44 </div>
    45 </Layout>
    46 );
    47};
    48
    49export default EditPage;

    Yang perlu diperhatikan disini adalah kita mendapatkan id dari url menggunakan useRouter:

    1...
    2import { useRouter } from "next/router";
    3...
    4 const { id } = router.query;
    5...

    Hal ini berbeda dengan langkah membuat Dynamic Routes menggunakan getStaticPaths() dan getStaticProps(), ini dilakukan karena AWS Amplify (bagian deployment) belum sepenuhnya support semua teknik prerendering Next.js.

    Dan langkah-langkah diatas bisa saja berubah dan akan diperbaharui setelah AWS Amplify support semua teknik prerendering termasuk teknik membuat dynamic routes menggunakan getStaticPaths() dan getStaticProps().

    Langkah selanjutnya adalah mengubah title pada NotesList menjadi link yang mengarah ke halaman untuk mengedit.

    components/NotesList.js

    1import React, { useEffect, useState } from "react";
    2import { API } from "@aws-amplify/api";
    3import Link from "next/link";
    4
    5import { listNotes } from "../graphql/queries";
    6
    7const NotesList = () => {
    8 ...
    9 return (
    10 <div className="flex flex-col items-center justify-center m-4">
    11 <div className="grid grid-cols-1 md:grid-cols-3 gap-4 my-8 overflow-y-auto">
    12 {notes &&
    13 notes.map((note) => {
    14 return (
    15 <div className="text-left p-4 border rounded-md" key={note.id}>
    16 <h4 className="text-lg font-semibold text-purple-900">
    17 <Link href={`/edit/${note.id}`}>{note.title}</Link>
    18 </h4>
    19 <p>{note.content.slice(0, 101)}</p>
    20 </div>
    21 );
    22 })}
    23 </div>
    24 </div>
    25 );
    26};
    27
    28export default NotesList;

    Hasil Akhir:

    8. Navigasi antar Halaman

    Setelah 3 halaman utama (Home, Add, Edit) dari aplikasi DinoTes sudah dibuat, yang perlu dilakukan selanjutnya adalah melengkapi navigasi antar halaman.

    Antara halaman depan (Homepage) dengan halaman edit sudah tersambung melalui link pada title, sedangkan Homepage dan halaman Add belum tersambung. Untuk itu kita akan tambahkan sebuah button pada Homepage sebagai penghubung.

    dinotes amplify page connection

    Update file Header.js menjadi seperti ini:

    components/Header.js

    1import React from "react";
    2import Link from "next/link";
    3import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
    4import { faFile } from "@fortawesome/free-solid-svg-icons";
    5
    6const Header = () => {
    7 return (
    8 <>
    9 <div className="flex justify-between items-center border-b-2 border-gray-100 py-6 md:justify-start md:space-x-3">
    10 <img
    11 className="h-14 w-auto sm:h-16"
    12 src="/header-logo.png"
    13 alt="logo"
    14 />
    15 <div className="md:flex items-center justify-end md:flex-1 lg:w-0">
    16 <Link href="/add">
    17 <button className="bg-purple-700 text-white text-base m-2 p-3 border rounded-md">
    18 <FontAwesomeIcon icon={faFile} />
    19 &nbsp;&nbsp; New Note
    20 </button>
    21 </Link>
    22 </div>
    23 </div>
    24 </>
    25 );
    26};
    27
    28export default Header;

    dinotes new note button header