Search by

    Terakhir diperbaharui: Oct 24, 2020

    Enhancement

    Code Enhancement yang akan kita lakukan kali ini:

    • Menampilkan pesan kesalahan / error ketika terjadi kesalahan, seperti kolom title yang tidak diisi.
    • Menampilkan notes sesuai urutan waktu ditambahkannya note

    Client Error Handler

    Pada pembahasan error handling sebelumnya, client tidak boleh membiarkan data title kosong.

    Jika data title kosong maka akan client akan menerima response error dalam bentuk JSON.

    Error dalam bentuk JSON mungkin tidak dipahami user.

    Oleh karena itu kita akan menggunakan component ui Message untuk menampilkan error yang lebih user friendly.

    Kita perlu update code component src/components/ui/Message.js agar dapat digunakan untuk menampilkan dua jenis pesan, pesan yang mewakili setiap operasi yang berhasil dan pesan untuk menampilkan kesalahan yang terjadi.

    1import React from 'react';
    2import styled from 'styled-components';
    3
    4const MessageContainer = styled.div`
    5 display: flex;
    6 flex-direction: column;
    7 align-items: center;
    8 justify-content: center;
    9 margin: 0.5rem;
    10 padding: 0 1rem;
    11 border: 2px solid ${(props) => (props.danger ? '#F56565' : '#68d391')};
    12 border-radius: 5px;
    13`;
    14
    15const Message = (props) => {
    16 const { text, type } = props;
    17
    18 return (
    19 <>
    20 {type === 'error' ? (
    21 <MessageContainer danger>
    22 <p>{text}</p>
    23 </MessageContainer>
    24 ) : (
    25 <MessageContainer>
    26 <p>{text}</p>
    27 </MessageContainer>
    28 )}
    29 </>
    30 );
    31};
    32
    33export default Message;

    Kemudian membuat sebuah component baru bernama InfoWrapper di dalam component AddNoteForm yang berfungsi untuk menampilkan pesan sesuai dengan respon dari REST API apakah note berhasil disimpan di dalam database atau tidak.

    src/components/AddNoteForm.js

    1import React, { useState } from 'react';
    2import { Form, FormGroup, Label, Input, TextArea } from './ui/Form';
    3import Button from './ui/Button';
    4import Message from './ui/Message';
    5
    6const InfoWrapper = (props) => {
    7 const { status } = props;
    8
    9 if (status !== null) {
    10 if (status === false) {
    11 return <Message type="error" text="Title harus diisi" />;
    12 }
    13 return <Message type="success" text="Data berhasil disimpan" />;
    14 }
    15 return <></>;
    16};
    17
    18const AddNoteForm = () => {
    19 const [state, setState] = useState({ title: '', note: '' });
    20 const [isSuccess, setIsSuccess] = useState(null);
    21
    22 const handleTitleChange = (e) => {
    23 setState({ ...state, title: e.target.value });
    24 };
    25
    26 const handleNoteChange = (e) => {
    27 setState({ ...state, note: e.target.value });
    28 };
    29
    30 const handleSubmit = (e) => {
    31 const requestOptions = {
    32 method: 'POST',
    33 headers: { 'Content-Type': 'application/json' },
    34 body: JSON.stringify(state)
    35 };
    36
    37 async function submitData() {
    38 const response = await fetch('http://localhost:3001/note', requestOptions);
    39 if (response.ok) {
    40 setIsSuccess(true);
    41 } else {
    42 setIsSuccess(false);
    43 }
    44 }
    45
    46 submitData();
    47
    48 e.preventDefault();
    49 };
    50
    51 const { title, note } = state;
    52
    53 return (
    54 <>
    55 <InfoWrapper status={isSuccess} />
    56 <Form onSubmit={handleSubmit}>
    57 <FormGroup>
    58 <Label>Title</Label>
    59 <Input type="text" name="title" value={title} onChange={handleTitleChange} />
    60 </FormGroup>
    61 <FormGroup>
    62 <Label>Note</Label>
    63 <TextArea name="note" rows="12" value={note} onChange={handleNoteChange} />
    64 </FormGroup>
    65 <FormGroup>
    66 <Button type="submit">Add</Button>
    67 </FormGroup>
    68 </Form>
    69 </>
    70 );
    71};
    72
    73export default AddNoteForm;

    Sekarang jika kita tidak menambah note tanpa mengisi kolom title maka akan muncul pesan kesalahan seperti ini:

    error message add note

    Lalu bagaimana dengan error yang diakibatkan oleh selain kolom title yang kosong?

    Untuk error handler yang bersifat lebih luas dan mencakup berbagai macam jenis error akan dibahas pada bagian Improve App.

    Selanjutnya adalah menambahkan error handler ini di halaman Edit.

    src/components/EditNoteForm.js

    1import React, { useEffect, useState } from 'react';
    2import { useLocation, useHistory } from 'react-router-dom';
    3import { Form, FormGroup, Label, Input, TextArea } from './ui/Form';
    4import Button from './ui/Button';
    5import Message from './ui/Message';
    6
    7const InfoWrapper = (props) => {
    8 const { status } = props;
    9
    10 if (status !== null) {
    11 if (status === false) {
    12 return <Message type="error" text="Title harus diisi" />;
    13 }
    14 return <Message type="success" text="Data berhasil disimpan" />;
    15 }
    16 return <></>;
    17};
    18
    19const EditNoteForm = () => {
    20 const location = useLocation();
    21 const history = useHistory();
    22 const [currentNote, setCurrentNote] = useState({ title: '', note: '' });
    23 const [isSuccess, setIsSuccess] = useState(null);
    24
    25 useEffect(() => {
    26 const noteId = location.pathname.replace('/edit/', '');
    27
    28 async function fetchData() {
    29 const response = await fetch(`http://localhost:3001/note/${noteId}`);
    30 const data = await response.json();
    31 setCurrentNote(data);
    32 }
    33
    34 fetchData();
    35 }, []);
    36
    37 const handleTitleChange = (e) => {
    38 setCurrentNote({ ...currentNote, title: e.target.value });
    39 };
    40
    41 const handleNoteChange = (e) => {
    42 setCurrentNote({ ...currentNote, note: e.target.value });
    43 };
    44
    45 const handleSubmit = (e) => {
    46 const options = {
    47 method: 'PUT',
    48 headers: { 'Content-Type': 'application/json' },
    49 body: JSON.stringify(currentNote)
    50 };
    51
    52 async function submitData() {
    53 const response = await fetch(`http://localhost:3001/note/${currentNote._id}`, options);
    54 if (response.ok) {
    55 setIsSuccess(true);
    56 } else {
    57 setIsSuccess(false);
    58 }
    59 }
    60
    61 submitData();
    62
    63 e.preventDefault();
    64 };
    65
    66 const handleDeleteNote = () => {
    67 const options = {
    68 method: 'DELETE',
    69 headers: { 'Content-Type': 'application/json' }
    70 };
    71
    72 async function deleteData() {
    73 const response = await fetch(`http://localhost:3001/note/${currentNote._id}`, options);
    74 if (response.ok) {
    75 history.push('/');
    76 }
    77 }
    78
    79 deleteData();
    80 };
    81
    82 const { title, note } = currentNote;
    83
    84 return (
    85 <>
    86 <InfoWrapper status={isSuccess} />
    87 <Form onSubmit={handleSubmit}>
    88 <FormGroup>
    89 <Label>Title</Label>
    90 <Input type="text" name="title" value={title} onChange={handleTitleChange} />
    91 </FormGroup>
    92 <FormGroup>
    93 <Label>Note</Label>
    94 <TextArea name="note" rows="12" value={note} onChange={handleNoteChange} />
    95 </FormGroup>
    96 <FormGroup>
    97 <Button type="submit">Save</Button>
    98 <Button danger onClick={handleDeleteNote}>
    99 Delete
    100 </Button>
    101 </FormGroup>
    102 </Form>
    103 </>
    104 );
    105};
    106
    107export default EditNoteForm;

    Update handler updateNote pada REST API agar sama dengan handler addNote, dimana data title harus tersedia di dalam body request.

    api/handler.js

    1...
    2exports.updateNote = async (req, res, next) => {
    3 const { notesCollection } = req.app.locals;
    4 const { title, note } = req.body;
    5
    6 try {
    7 if (!title) {
    8 throw new Error('title is missing');
    9 }
    10 // update data collection
    11 const result = await notesCollection.updateOne(
    12 { _id: ObjectId(req.params.id) },
    13 { $set: { title, note } }
    14 );
    15
    16 console.log(result);
    17
    18 res.status(200).json('Data successfully updated');
    19 } catch (error) {
    20 next(error);
    21 }
    22};
    23...

    Sorting

    Pada halaman utama aplikasi DinoTes, semua notes ditampilkan dengan urutan note yang terlama di atas dan note yang terbaru dibawah.

    Kita bisa ganti tampilannya menjadi note yang terbaru yang ditampilkan paling atas.

    Mengurutkan atau sorting bisa dilakukan baik di sisi client atau server.

    Menambahkan lebih banyak tugas seperti sorting di dalam React bukanlah ide yang bagus ketika kita sudah memiliki sebuah API.

    Lebih baik membiarkan React melakukan tugas dasarnya yaitu rendering element / component sesuai data yang ada.

    Oleh karena itu kita akan melakukan proses sorting di sisi server / Express.js.

    Kita bisa memanfaatkan method sorting yang dimiliki oleh MongoDB.

    api/server.js

    1exports.getAllNotes = async (req, res, next) => {
    2 const { notesCollection } = req.app.locals;
    3
    4 try {
    5 // find all Notes
    6 const result = await notesCollection.find().sort({_id:-1}).toArray();
    7
    8 res.status(200).json(result);
    9 } catch (error) {
    10 next(error);
    11 }
    12};

    method sort({_id:-1}) akan mengurutkan data sesuai dengan waktu data tersebut ditambahkan ke database.

    Catatan

    Perlu diperhatikan bahwa enhancement di atas bersifat optional, yang berarti tanpa enhancement aplikasi DinoTes sudah bisa digunakan.

    Tapi jika kita ingin aplikasi kita menjadi aplikasi yang tidak hanya menyelesaikan masalah tapi juga mudah digunakan, maka kita perlu memperhatikan pengalaman user atau user experience (UX) dalam menggunakan aplikasi tersebut.

    Dan kita bisa melakukannya dengan menambah fitur-fitur dasar yang memang hal itu dapat membantu user dalam menggunakan aplikasi.

    Tapi tidak terlalu berlebihan...

    Karena menambahkan fitur yang sebenarnya tidak terlalu dibutuhkan user justru akan membuat aplikasi menjadi lebih kompleks dari yang seharusnya.

    Sehingga berpotensi menurunkan kualitas UX itu sendiri dan aplikasi menjadi lebih rentan terhadap bugs.

    Masih sedikit

    Enhancement yang kita lakukan di atas bisa dibilang sangat sedikit, sebagai contoh pada bagian sorting seharusnya kita tidak membatasi user dengan hanya menampilkan note dengan urutan dari yang terbaru ke yang terlama.

    Kita seharusnya bisa menambahkan sebuah menu dalam bentuk drop down atau semisalnya yang memungkinkan user untuk melakukan sorting dengan berbagai pilihan.

    Seperti mengurutkan note dari waktu pembuatannya (Newest/Oldest Created Date) atau waktu modifikasinya (Newest/Oldest Modified Date).

    Dan bentuk enhancement yang lainnya.

    Kita akan lebih banyak melakukan enhancement yang bertujuan untuk meningkatkan kualitas dari aplikasi tersebut baik dari sisi UX ataupun performa aplikasi pada pembahasan Improve App.

    Contoh enhancement atau improvement yang akan kita bahas: menambahkan search, authentication, logger, custom sorting dll.