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';34const MessageContainer = styled.div`5678910111213`;1415const Message = (props) => {16 const { text, type } = props;1718 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};3233export 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';56const InfoWrapper = (props) => {7 const { status } = props;89 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};1718const AddNoteForm = () => {19 const [state, setState] = useState({ title: '', note: '' });20 const [isSuccess, setIsSuccess] = useState(null);2122 const handleTitleChange = (e) => {23 setState({ ...state, title: e.target.value });24 };2526 const handleNoteChange = (e) => {27 setState({ ...state, note: e.target.value });28 };2930 const handleSubmit = (e) => {31 const requestOptions = {32 method: 'POST',33 headers: { 'Content-Type': 'application/json' },34 body: JSON.stringify(state)35 };3637 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 }4546 submitData();4748 e.preventDefault();49 };5051 const { title, note } = state;5253 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};7273export default AddNoteForm;
Sekarang jika kita tidak menambah note tanpa mengisi kolom title maka akan muncul pesan kesalahan seperti ini:
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';67const InfoWrapper = (props) => {8 const { status } = props;910 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};1819const EditNoteForm = () => {20 const location = useLocation();21 const history = useHistory();22 const [currentNote, setCurrentNote] = useState({ title: '', note: '' });23 const [isSuccess, setIsSuccess] = useState(null);2425 useEffect(() => {26 const noteId = location.pathname.replace('/edit/', '');2728 async function fetchData() {29 const response = await fetch(`http://localhost:3001/note/${noteId}`);30 const data = await response.json();31 setCurrentNote(data);32 }3334 fetchData();35 }, []);3637 const handleTitleChange = (e) => {38 setCurrentNote({ ...currentNote, title: e.target.value });39 };4041 const handleNoteChange = (e) => {42 setCurrentNote({ ...currentNote, note: e.target.value });43 };4445 const handleSubmit = (e) => {46 const options = {47 method: 'PUT',48 headers: { 'Content-Type': 'application/json' },49 body: JSON.stringify(currentNote)50 };5152 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 }6061 submitData();6263 e.preventDefault();64 };6566 const handleDeleteNote = () => {67 const options = {68 method: 'DELETE',69 headers: { 'Content-Type': 'application/json' }70 };7172 async function deleteData() {73 const response = await fetch(`http://localhost:3001/note/${currentNote._id}`, options);74 if (response.ok) {75 history.push('/');76 }77 }7879 deleteData();80 };8182 const { title, note } = currentNote;8384 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 Delete100 </Button>101 </FormGroup>102 </Form>103 </>104 );105};106107export 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;56 try {7 if (!title) {8 throw new Error('title is missing');9 }10 // update data collection11 const result = await notesCollection.updateOne(12 { _id: ObjectId(req.params.id) },13 { $set: { title, note } }14 );1516 console.log(result);1718 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;34 try {5 // find all Notes6 const result = await notesCollection.find().sort({_id:-1}).toArray();78 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.