Bedah Code 03-04-2020 : React Full Stact, Express, PostgreSQL (Part 2)

Artikel ini adalah bagian dari latihan saya dalam membuat aplikasi dengan cara mempelajari code milik orang lain. Cara belajar seperti ini saya gambarkan di artikel berikut : Latihan Programming Dengan Cara 'Membedah' Code Buatan Orang Lain. Code yang kali ini saya bahas adalah code buatan Mohammad Iqbal yang ditulis di website FreeCodeCamp berikut: Full Stack React: How to Build Your Own Blog Using Express, Hooks, & Postgres.

Ini adalah artikel bagian kedua. Bagian pertama bisa ditemukan di sini. Bagian ketiga dapat ditemukan di sini.


---------

Selanjutnya kita akan membuat component untuk blog clientnya, secara spesifik, yaitu addpost.js, editpost.js, posts.js, showpost.js, profile.js, showuser.js. Addpost adalah component untuk membuat posts. Editposts adalah component untuk edit posts. Posts adalah component yang menampilkan semua posts. Showpost adalah component yang menampilkan post tunggal. Profile adalah component yang menampilkan laman profile user yang sedang login, mungkin seperti dashboard user. Showuser adalah component yang menampilkan profile user lain dan bukan dashboard user.

Aliran data pada website kita adalah dari form di frontend, lalu ke axios, lalu ke server express, lalu ke database. Kita tidak memakai Redux Form atau ORM (Object-Relational Mapping) karena prosedur kita cukup sederhana dan tidak memerlukan fitur lebih rumiti Redux Form atau ORM.

ADDPOST.JS
Di file ini, pertama kita ambil object Context. Di dalam object tersebut ada informasi soal authentication kita, misalnya profil kita apa. Ini supaya ketika kita menyimpan post, konten postnya tersimpan di database sesuai profil kita. Di bagian html di sini ada dua bagian, yaitu form title dan form body. Keduanya dikelola dengan handleSubmit ketika tombol Submit ditekan. Form title dan body tersebut dikelola di dalam component TextField. Selain tombol submit ada tombol Cancel juga yang mengarahkan ke route /posts memakai library history. Semua function addpost ini dibalut di dalam component AddPost().
Di sini elemen yang paling ekstensif adalah function handleSubmit. handleSubmit menerima object event dari frontend. Dia ambil user_id dan username dari Context, secara spesifik dari bagian dbProfileState. Dari object Event, dia ambil value title dan body. Semua data itu dimasukkan ke dalam object data. Object data tadi diteruskan melalui function axios.post ke route posttodb. Lalu ada bagian respons dan err, mungkin untuk menangkap log kalau operasi berjalan sukses atau error. Selain itu ada function setTime out yang di set selama 700 ms, kemungkinan untuk menjaga supaya api tidak kelamaan terbuka? Ada juga function event.preventDevault supaya laman tidak refresh. Component TextField ini ternyata berasal dari library material-ui, yang artinya pelingkupan form ke dalam component TextField itu berhubungan dengan styling dan tidak ada function tambahan di situ.

EDITPOST.JS
Component ini adalah component tempat mengedit post dan hanya bisa diakses melalui laman profile user. Di bagian htmlnya ada bagian TextField yang membungkus bagian title dan body. Di bawahnya da tombol Submit dan Cancel sama seperti di addpost. Tombol Cancelnya tidak mengarahkan ke posts, tapi memakai function goBack dari library history. Di bagian title atau pun body ada function onChange yang mengelola perubahan dan ini functio ini diteruskan ke function handleTitleChange. Value dari kedua form tersebut dimasukkan ke dalam object stateLocal.
Function utama di component ini ditangani di bawah function EditPost. EditPost menerima parameter props. Dia mengambil context melalui useContext. Dia mendeklarasikan hook state local untuk menampung perubahan post, yaitu dengan variable stateLocal dan setState. State awalnya adalah props.location.state.post.post.title dan props.location.state.post.post.body. Ini nama yang cukup panjang dan mesti ditelusuri lagi asal-usulnya. Kemungkinan dia berasal dari props yang dideklarasikan di component yang memanggil component EditPost ini. Selanjutnya dia punya function handleTitleChange dan handleBodyChange yang menerima event dan menampung perubahan di body dan title.
Function handleSubmit menerima object event dari form di html. Dia mengambil property title dan body dari event itu. Dia juga ambil property username dan user_id dari context, lebih spesifik dari dbProfileState. Dia ambil post id (pid) dari props. Ini kemungkinan didapat dari props yang dideklarasikan di tempat EditPost ini pertama kali dipanggil. Semua data itu dimasukkan sebagai property di object data. Object data ini kemudian dimasukkan ke function axios.put yang meneruskan ke route /api/put/post yang nantinya akan memasukkan data ke database. Selain itu ada juga prosedur standar soal log res dan catch err, lalu ada lagi setTimeOut yang me-replace laman jadi /profile setelah 700 ms. Lalu ada juga event.preventDefault yang mencegah laman me-refresh. stateLocal pada form ini sepertinya tidak berhubungan langsung dengan value yang akan masuk ke database. Dia hanya bertugas menampilkan value body dan title dari value yang sudah ada di database, lalu menampilkan kembali ke form sesuai apa yang sudah diketik oleh user. Jadi dia tidak mesti berhubungan langsung dengan function yang memasukkan datanya ke dalam database. Function history.goBack sepertinya berfungsi untuk mengarahkan ke laman sebelumnya yang ditelusuri oleh browser.
Jadi kalau mau diringkas, alur datanya adalah pertama stateLocal memanggil data form dari database yang sudah ada. Kemudian dia ditampilkan di laman. Ketika ada perubahan, function handleBodyChange dan handleBodyTitle mengubah stateLocal. Ketika tombol submit ditekan, value di form dimasukkan ke database. Jadi bukan stateLocal yang dimasukkan ke database.
props.location.state.posts.posts. ternyata adalah funcionality dari react-router. Poinnya adalah bahwa data dari post yang diklik user akan masuk ke variable yang berbeda dari localState.

POSTS.JS
Posts.js adalah component yang menampilkan semua post. Di sini ada tombol buat menambah post baru (Add Post) yang mengarah ke route addpost. Lalu ada tombol signup yang mengarah ke route signup. Ada component TextField untuk search post. Di bawah search ini ada code untuk menampilkan hasil. Tampilan hasil akan muncul kalau ada search, kalau tidak ada search dia tidak muncul.
Selanjutnya ada bagian Posts yang sepertinya menampilkan hasil posts dengan cara memanggil component RenderPosts. Setelah itu ada pagination, yaitu pengaturan navigasi halaman. Pagination ini dibalut dalam class FlexRow. Ada tombol First, Previous, Next, Last. Standar seperti di forum atau blog biasa.
Tampilan hasil search memakai function .map untuk iterate post di database sepertinya. Tampilan Posts memakai function .map juga. Selain itu dia pakai property .posts_slice.
Pagination untuk tombol First memakai function page_change. Untuk tombol Prev dia memakai page_change yang mengolah state stateLocal.currentPage. Selanjutnya ada barisan code yang mengatur sutu tampilan variable page yang mungkin menampilkan barisan nomor laman yang tersedia. Selanjutnya ada tombol Next yang memakai penambahan 1 dari stateLocal.currentPage. Lalu ada tombol Last yang diatur dengan stateLocal.max_page.
Semua elemen di file posts.js ini dibalut dalam nama component Posts.
Posts.js mengimport useContext, useEffect, useState. Dia juga import Link dari react-router-dom, axios, moment, Context. Untuk tampilan, dia import Button, TextField, Card, CardContent, CardHeader, app.css, dan pagination.css.
Posts menerima props. Dia mengambil context melalui useContext. Dia mendeklarasikan state di stateLocal dengan value awal berupa object dengan banyak property. Property tersebut yaitu array posts, boolean fetched, boolean first_page_load, array pages_slice, int max_page, int items_per_page, int currentPagge, int num_posts, post_slice ini mungkin String, array posts_search, int posts_per_page. Yang dimaksud dengan istilah slice itu mungkin potongan dari nilai aslinya. Jadi kalau post slice itu sebagian dari teks post, kalau pages slice itu sebagian dari nomor halaman untuk kepentingan pagination.
Component ShowPost dipanggil di routes Client tapi tidak diberikan props. Sepertinya props di parameter constructor ShowPost itu tidak dimasukkan pada saat ShowPost dipanggil tapi itu dipakai untuk menunjukkan post yang saat itu sedang dibuka. Dan object props ini memiliki state di dalamnya dan state tersebut dipakai untuk mengisi function di dalam component itu.
Pertama ada function useEffect dengan if statements. Jika postState ada, dia akan mengambil data semua post dari database melalui route /api/get/allposts memakai axios. Di axios ini setelah get dia akan mendapatkan respons dan respons (res) ini akan diteruskan ke function handleAddPosts. Error akan ditangkap dengan catch. Variable postsState ini ada di Context.Provider. Variable postsState ini di Context menunjuk kepada object atau variable posts yang sedang di-handle di component PostsReducer.
Parameter props pada constructor component Posts itu dipakai untuk mengambil object penanda entitas yang sedang dibuka sekarang. Dari entitas itu ada property-property yang bisa dipakai di dalam function-function di dalam compenent tersebut.
Selanjutnya, apabila object postState ada dan stateLocal belum di-fetched (value fetched-nya masih false), maka ada beberapa variable yang di set, yaitu indexOfLastPost jadi 1 kali stateLocal.posts_per_page. Ini maksudnya post terakhir yang akan ditampilkan di halaman posts itu adalah post dengan nomor urut jumlah maksimal post per laman. Jumlah maksimal post per laman sepertinya akan bisa di-set oleh user nanti. Selain itu, indeOfFirstPost akan jadi indexOfLastPost – stateLocal.posts_per_page. Ini maksudnya index post pertama adalah index post terakhir dikurangi jumlah maksimal post per laman. Kalau dijadikan variable seperti ini, kemungkinan besar index post pertama itu tidak selalu 0 atau 1. Selanjutnya ada variable last_page, yaitu pembulatan ke atas dari jumlah post yang sedang kita handle dibagi jumlah post per laman. last_page ini berarti akan menghasilkan angka laman terakhir dari laman-laman yang memuat posts yang sedang kita handle.
Selanjutnya, masih dalam lingkup ada postsState tapi belum difetched, ada perubahan property stateLocal, yaitu status fetched menjadi true, posts akan diisi oleh post yang sedang kita handle yaitu yang sedang ditangani oleh PostsReducer, num_posts diisi oleh angka jumlah post yang sedang kita tangani, posts_slice diisi oleh post yang sedang kita tangani dimasukkan ke function slice dengan parameter indexOfFirstPost dan indexOfLastPost. Function slice adalah function Javascript yang mengambil irisan dari suatu array mulai dari index yang kita tulis di parameter pertama sampai index yang kita tulis di parameter kedua. Dalam hal ini berarti dari array post-post yang sedang kita tangani (baik dari keseluruhan post atau post yang kita ‘search’), kita hanya menampilkan post dari index post pertama dari laman sampai ke post index terakhir dari laman.

Kemudian, useEffect ini dilanjutkan dengan parameter kedua selain dari function if statements tadi. Parameter kedua ini maksudnya adalah function useEffect akan dieksekusi ketika parameter kedua tersebut berubah. Dan parameter kedua di useEffect kita adalah array [context, stateLocal]. Ini artinya useEffect akan dieksekusi lagi ketika context atau stateLocalnya berubah.

Setelah itu, ada function useEffect kedua. useEffect kedua ini sepertinya untuk mengatur pagination. Di sini dia mendeklarasikan variable page yang isinya angka halaman yang sedang dibuka. Lalu ada variable indexOfLastPost yang isinya page * 3. Perlu diingat bahwa indexOfLastPost ini isinya angka jumlah post maksimal dalam suatu laman. Kemudian ada variable indexOfFIrstPost yaitu indexOfLastPost dikurangi 3.
Lalu di useEffect kedua ini ada setState yang diisi dengan posts_slice yaitu potongan dari indexOfFirstPost dengan indexOfLastPost di stateLocal. Perlu diingat bahwa stateLocal ini salah satu isinya adalah array dari posts yang kita sedang tangani. Salah satu perbedaan dengan useEffect yang pertama adalah di useEffect kedua ini parameter keduanya adalah array [stateLocal. currentPage]. Jadi ketika stateLocal.currentPage ini berubah, useEffect kedua ini akan dieksekusi. Secara spesifik, ketika user berpindah laman posts ke nomor laman selanjutnya, isi variable post_slice-nya akan berubah dan isi variable ini akan menentukan pagination.

Selanjutnya ada function add_search_posts_to_state. Function ini mengubah stateLocal. Pertama dia menginisiasi array posts_search, yaitu array yang nantinya menampung posts hasil pencarian. Selanjutnya baru array tersebut diisi dengan variable posts, yaitu object posts yang akan ditampilkan.

Selanjutnya ada function handleSearch yang menerima object event. Fungsinya mestinya adalah menerima input search lalu mengolah input untuk memberikan hasil yang diinginkan. Pertama, dia menginisiasi arrah posts_search di dalam stateLocal. Lalu dia mengambil value input yang dimasukkan user ke dalam variable search_query. Variable search_query ini diteruskan ke fungsi axios get untuk diteruskan ke route /api/get/searchpost sebagai parameter pencarian database. Hasil pencariannya akan otomatis masuk ke variable res. Variable res ini dievaluasi, kalau panjangnya 0, dia akan return null. Kalau panjangnya tidak sama dengan 0, dia akan memasukkan res.data ke function add_search_posts_to_state yang kita deklarasikan sebelumnya. Kita juga akan me-console.log error kalau ada.

Selanjutnya adalah function RenderPosts yang menerima variable object post. Function ini berfungsi menampilkan hasil request baik itu hasil pencarian atau semua posts ke laman. Di sini ada dua elemen utama, yaitu component CardHeader dan CardContent. Keduanya dibalut dalam component Card. Semua elemen Card ini adalah bagian dari library material-ui yang menyediakan template yang siap pakai. Di dalam CardHeader ada htlm tag title yang isinya component Link menuju pathname post ditambah post id. Link ini menerima property state juga yang dalam hal ini diisi variable post. Link ini membalut variable post.post.title. Link ini adalah bagian dari library react router dom. Penjelasan soal bagaimana property to di component Link ini bisa menerima 2 variable itu mungkin bisa ditemukan di documentationnya. Selain elemen title, di dalam CardHeader juga ada elemen subheader. Di sini ada elemen html class FlexColumn dan FlexRow. Sepertinya ini bentuknya akan seperti kolom dengan 2 baris. Baris pertama adalah tanggal pembuatan, baris kedua adalah nama pembuat, baris ketiga adalah likes. Baris pertama, yaitu tanggal dibuat dengan memanfaatkan function library moment yang mengambil variable post.post.date_created. Library moment ini sepertinya library untuk mengolah data tanggal. Sepertinya tidak ada fungsi khusus lain.
FlexRow selanjutnya adalah untuk author. Bagian ini diisi dengan component Link yang berisi pathname diikuti variable post.post.autor. Dalam component ini juga ada state post. Link ini membalut post.post.author.
FlexRow selanjutnya adalah likes. Dia memakai icon thumb_up dari material_ui. Selanjutnya dia juga berisi variable post.post.like yang sepertinya adalah jumlah like di suatu post.
Setelah CardHeader, ada bagian CardContent. Isi bagian ini adalah span yang berisi variable post.post.body dengan style hidden. Sepertinya bagian ini akan terbuka hanya kalau diberikan perlakuan seperti klik atau hover. Di sini tidak memakai fungsi slice jadi kemungkinan besar kalau terbuka, yang terbuka adalah semua kontennya tidak hanya potongannya.
Component RenderPosts ini mengatur tampilan satu post saja, tidak semuanya sekaligus. Kemungkinan besar di bagian returnnya akan diatur tampilan dari banyak component RenderPosts.
Setelah bagian RenderPosts ada function page_change. Ini adalah function terakhir di component ini. Function ini menerima object/variable page. Di dalamnya kebanyakan adalah statement if yang berkaitan dengan posisi user di laman. Sepertinya function ini adalah untuk mengatur penunjukkan link, khususnya link Prev dan Next di bagian navigasi laman post/pencarian. Pertama, di function ini ada function window.Scrollto yang mungkin berfungsi untuk menggeser layar ke bagian atas laman ketika terjadi perubahan laman. Selanjutnya ada deklarasi variable next_page yaitu page + 1, dan variable prev_page, yaitu page  - 1. Ada lima kondisi if statement. Yang pertama adalah ketika posisi page kita ada di page lebih dari 2 dan kurang dari laman terakhir – 1. Kedua adalah ketika page kita sama dengan 2. Ketiga adalah ketika page kita sama dengan 1. Keempat adalah ketika kita di page terakhir, kelima adalah ketika kita di satu laman sebelum laman terakhir. Di dalam tiap if statement itu kita hanya mengatur state 2 property di dalam stateLocal, yaitu currentPage dan pages_slice. Di dalam tiap if statement itu, page akan di-set jadi currentPage. pages_slice ini kemungkinan besar adalah angka-angka laman tertentu yang ditampilkan di navigasi sesuai di mana posisi page kita saat itu.
Untuk if statement yang di posisi page lebih dari 2 dan page di bawah dari jumlah maksimal page dikurangin 1, itu berarti mulai muncul link Prev dan Next. Jadi ada 5 elemen maksimal di tiap pages_slice. Jadi untuk if statement ini ada link Prev - 1, Prev, current page, Next, Next + 1.
Untuk if statement di posisi page sama dengan 2, ada link Prev, Page, Next, Next + 1, Next + 2.
Untuk if statement di posisi page sama dengan 1, ada link Page, Next, Next + 1, Next + 2, Next + 3.
Untuk if statement di posisi page di laman terakhir, ada link Prev – 3, Prev – 2, Prev – 1, Page.
Untuk if statement di posisi page di 1 laman sebelum laman terakhir, ada link Prev – 2, Prev – 1, Page, Next.
Jadi pages_slice itu adalah kumpulan angka di navigasi laman tampilan post, page itu variable yang menyimpan posisi post sekarang. Jadi di tiap navigasi laman tampilan post itu selalu ada 5 angka atau 5 link. Posisi laman sekarang diusahakan ada di tengah-tengah.
Jadi katanya pemakaian useEffect itu karena kita menyimpan panggilan posts ke global state, supaya kita tetap memunculkan posts itu meskipun kita pindah ke laman lain. Ya ini diperlukan terutama ketika kita pindah laman dari navigasi laman hasil pencarian.
Perubahan laman juga bisa dilakukan secara manual dengan form. Jadi user bisa langsung menuju laman hasil pencarian yang dituju.
Kemudian ada class CSS yang mengatur tampilan pagination, secara spesifik yaitu warna nomor alaman ketika aktif (sudah ditekan?) atau ketika belum ditekan atau ketika sedang di-hover. Class CSS ini dipasang di file tersendiri.

Selanjutnya kita akan membuat css khusus untuk pagination. pagination.css ada di dalam folder /src/styles di folder Client. Di css ini ditentukan bahwa kalau link itu active, background colornya akan jadi biru, tulisannya akan jadi putih. Ketika di-hover, background colornya adalah abu-abu.

SHOWPOST.JS

Kita ke bawah dulu ke bagian return. Component ini mereturn 3 dif, yaitu Post, daftar Comments, dan form Comments. Bagian likes digabung dengan bagian Post. Pertama, Post ini diawali dengan ternary, yaitu jika stateLocal.comments_arr ada atau props.location.state ada, dia akan me-render judul, konten, dan nama author yang dikandung dalam stateLocal. Jika tidak ada, dia akan return null. comments_arr itu salah satu property stateLocal. Dia menampung object comments. Nanti dia akan menampung comments dari database. Sementara props.locations. state itu sepertinya mengandung banyak property yang nanti dijabarkan dalam berbagai function misalnya body, title, author. Sepertinya props.location.state itu mengandung object yang disalurkan dari component lain. Dalam hal ini, dia membawa object post yang akan kita tampilkan. Kita akan coba selidiki lebih lanjut di bagian function di component ini. Sementarai itu, selama comments.arr ada atau props.location.state ada, maka component ini akan me-render div berisi post title, body, dan author. Kalau tidak ada, dia akan me-return null.
Setelah itu, di bagian bawah Post ada tombol like yang berbentuk thumb_up memakai material-icons. Tombol ini dipasangkan statement ternary, yaitu ketika sudah login, function handleLike akan terpicu. Jika belum login, dia akan mengarahkan ke route /signup. Lalu ada penanda jumlah likes yang diakses melalui stateLocal.likes.

Selanjutnya ada bagian Comments. Lagi-lagi di sini ada ternary yang menguji apakah ada comments_arr. Jika ada, isi comments_arr itu akan di map dan isinya akan dihandle dan ditampilkan oleh komponen RenderComments. RenderComments di bagian return ini berisi ternary apakah ada profileState dari database yang menunjuk ke pemberi komentar. Jika tidak ada, dia akan memunculkan null. selain ternary ini, dia akan memunculkan property comment itu sendiri, lalu comment id, lalu ada function boolean untuk edit, yaitu isEditing. boolean isEditing mengecek apakah commet id itu sama dengan comment yang sedang di edit, yaitu di variable edit_comment_id. Jika sama, isEditing akan true, berlaku sebaliknya.

Setelah itu ada form untuk komentar. Ada TextField untuk menampung input user. Lalu ada lagi ternary yang mengecek status authentication, yaitu object context.authState. JIka authentication ada, maka muncul tombol submit yang nantinya akan meneruskan data di TextField. Jika belum ada authentication, makan ada tombol Signup yang mengarahkan ke route /signup.
Semua function di file ini dibalut dalam component ShowPost.

ShowPost mengimport useState, useContext, useEffect, Link dari react-router-dom, axios, history, Context, TextField, Button dari material-ui.
ShowPost dideklarasikan bersama dengan parameter props. Pertama dia akan mengambil context dengan useContext.
Lalu dia akan mendeklarasikan state, yaitu stateLocal dengan useState. stateLocal memiliki banyak property, antara lain comment, fetched, cid, delete_comment_id, edit_comment_id, edit_comment, comments_arr, cur_user_id, like_post, likes, like_user_ids, post_title, post_body, post_auhor, post_id. Pada dasarnya ini semua adalah data yang diperlukan untuk menampilkan post ke user. Jadi component ini akan me-request data post dari database lalu akan menerimanya dan data tersebut akan ditampung dalam property-property di stateLocal ini..
Di component ini ada 3 function useEffect, beberapa function untuk mengurus comment. Beberapa function untuk comment yaitu submit, update, delete, render, edit form close, edit comment change. Kemudian ada lagi function untuk submit, delete, update comment. Function untuk mengurus comment ini seakan berganda, tapi ini mungkin karena salah satu pasangan function submit / delete / update itu untuk mengurus tampilan, sementara satu pasangan lagi untuk benar-benar mengeksekusi operasi ke database. Kita akan cek lagi ini nanti. Kemudian ada function untuk mengurus likes.
Yang pertama adalah useEffect pertama. Isi useEffect ini hanya satu if statement. Jika props.location.state ada dan localState belum di-render, yaitu stateLocal.fetched masih false, maka stateLocal akan diisi propertynya oleh props.location.state yang baru masuk yang disalurkan dari komponen lain (sepertinya dari global context config). Lalu value fetchednya jadi true. Parameter kedua dari useEffect ini adalah array stateLocal dan props.location, yang artinya sepertinya function useEffect pertama ini akan dieksekusi lagi kalau kedua variable tadi berubah.
Selanjutnya adalah function useEffect kedua. useEffect kali ini juga berisi satu if statement. Jika props.location.state tidak ada dan stateLocal belum di-render, maka akan dieksekusi function yang memanggil data post dari database. Pertama dideklarasikan dulu variable post_ide yang mengambil nama dari pathname dari props.location.pathname. Jadi ini mungkin dia mengambil postid dari nama url yang akan di-render. post_id ini diteruskan ke function axios.get ke database dengan parameter post_id lalu mendapatkan respons berupa res. Kemudian ada ternary bahwa jika ada res.data yang masuk, property stateLocal akan diisi dengan data dari res. Jika tidak ada data dari res maka hasilnya akan null. Setelah itu ada code buat catch error juga. Parameter kedua useEffect kedua ini adalah stateLocal dan props.location juga yang sepertinya berarti useEffect ini akan dieksekusi lagi ketika kedua variable itu berubah.

Selanjutnya ada useEffect ketiga yang mengurusi komentar. useEffect ini juga terdiri dari satu if statement yang mengecek apa ada comments.arr. Jika ada maka masuk lagi ke ke if statement selanjutnya yang mengecek apa ada props.location.state. Selanjutnya dia akan membuat variable post_id untuk memasukkan value pathname yang sedang dibuka. Variable post_id ini kemudian diteruskan ke database untuk mendapatkan comment yang dimasukkan ke comment_arr. Kemudian ada catch error juga. Seperti sebelumnya, useEffect ini dieksekusi kalau props.location dan stateLocal berubah.
Selanjutnya adalah function handleCommentSubmit yang mengambil parameter submitted_comment. Isi function ini adalah memasukkan submitted_comment ke comments_arr. JIka sudah ada comment_arr, maka submitted_comment ditambahkan ke array melengkapi komenter sebelumnya. Jika belum ada comment_arr maka submitted_comment ditambahkan sebagai komentar pertama. Function ini sederhana, tapi fungsi submit comment juga dilakukan fungsi lain di bawah yang lebih rumit.

Selanjutnya adalah function handleCommentUpdate yang menerima parameter comment. Pertama dideklarasikan variable commentIndex. Variable ini menampung index dari comment yang idnya sesuai dengan variable parameter comment yang dimasukkan ke constructor funtion handleCommentUpdate. Kemudian dibentuk array baru newArr yang isinya comments_arr. Kemudian dari array baru ini, comment yang indexnya sama dengan comment yang kita masukkan ke parameter kita ganti jadi comment yang masuk ke parameter. Singkatnya, comment yang tadinya ada di comments_arr (sepertinya ini comment dari database) kita ganti jadi comment yang masuk ke parameter. Selanjutnya ada setTime out yang menetapkan comments_arr isinya jadi newArr dan edit_comment_id diubah lagi jadi 0.

Selanjutnya ada function handleCommentDelete yang menerima parameter cid, yaiut comment id. function ini mengubah stateLoca yaitu property delete_comment_id-nya jadi cid. Lalu dia membuat array baru dengan function filter di mana di dalam array baru itu tidak ada cid yang sama dengan cid yang dimasukkan ke parameter.

Selanjutnya ada function handlerEditFormClose yang tidak menerima parameter dan isinya hanya penentuan property di dalam stateLocal yaitu edit_comment_id jadi 0. Ini mungkin maksudnya menghilangkan status keberadaan comment yang sedang diedit.

Selanjutnya ada component RenderComments yang menerima parameter props. Component ini me-return elemen html. Prosedur pertama yang kita temukan adalah pada className di tag div, yaitu ternary apakah property delete_comment_id di dalam stateLocal sama dengan props.comment.cid. Bila ya, maka comment ini akan di fade out dengan class FadeOutComment. Bila tidak, makan ia akan di-render dengan CommentStyles. Jadi RenderComments ini menangani satuan comment. Mungkin ia akan dimasukkan ke dalam function map nanti. Selanjutnya ada pe-render-an property comment di dalam props. Lalu ada ternary lagi yang menentukan apakah property date_created di dalam props itu sama dengan String Just Now. Jika iya maka ia akan diberikan span tertentu yang akan ketemu ternary lagi. Jika tidak, maka ia akan diberikan value tanggal pembuatan saja. Ternary untuk Just Now ini kemudian mengecek apakah masih ada property true untuk isEdited di props. Jika ada, maka akan muncul span Edited, jika tidak ada, maka muncul span Just Now.
Selanjutnya ada pe-renderan nama author dari props.
Selanjutnya di bawah ada bagian untuk edit komentar yang isinya beberapa ternary. Ternary pertama mengecek apa property props..cur_user_id sama dengan props.comment.user.id. Ini mungkin maksudnya mengecek apakah user yang sedang membuka laman itu sama dengan comment yang diinginkan untuk diedit. Kalau beda, maka akan muncul null. Jika iya, maka muncul ternary lagi apakah props.isEditing sedang true atau tidak. Jika lagi false, akan muncul button yang isinya function untuk mengubah property di stateLocal, yaitu edit_comment_id menjadi props.comment.cid dan edit_comment jadi props.comment.comment. Pada dasarnya ini menunjuk comment yang akan diubah baik id maupun kontennya. Bila props.isEditing jadi true, maka akan muncul form yang berisi input yang sudah di-populate dengan isi comment sebelumnya. Input ini diberi id editted_comment dan name edit_comment, lalu ada function onChange yang menunjuk ke function handleEditCommentChange. Form ini dipasangkan function onSubmit yang menerima parameter event dan cid yang kemudian diteruskan ke function handleUpdate yang membawa parameter event, cid tadi. Di bawah bagian input ada beberapa button. Button pertama yaitu Agree yang mengeksekusi submit. Button kedua, yaitu cancel mengeksekusi function handleEditFormClose. Button ketiga mengeksekusi function handleDeleteComment untuk comment tersebut.

Selanjutnya ada function handleEditCommentChange yang menerima parameter event lalu mengubah stateLocal di property edit_comment menjati event.target.value, yaitu input yang dimasukkan user ke form edit comment.

Selanjutnya ada function handleSubmit yang menerima parameter event yang mengubah property stateLocal edit_comment menjadi isi dari input yang dimasukkan user.

Selanjutnya ada function handleSubmit yang menerima parameter event. Pertama ada function preventDefault yang mencegah laman me-refresh. Lalu dia mengubah property comment di stateLocal jadi kosong. Lalu dibuat variable comment baru yang menampung value comment yang diinput user. Ada variable user_id dan username yang menerima data dari context database, yaitu data uid dan username. Lalu ada variable post_id yang menampung value post_ide dari stateLocal. Lalu ada variable current_time yang berisi String Just Now. Ada variable temp_cid yang mungkin untuk menentukan angka id comment karena dia memakai function Math.random. Lalu ada variable submitted_comment yang merupakan object berisi property cid, comment, user_id, author, date_created yang memakai variable yang sebelumnya dideklarasikan. Lalu ada variable data yang merupakan object berisi property comment berisi comment yang diinput dari form, lalu ada post_id, user_id, username. Lalu ada function axios yang meneruskan data di variable data di atas ke data base ke route commenttodb. Lalu ada console.log res dan error. Lalu window di-scroll ke atas sepertinya. Lalu ada pemanggilan function handleCommentSubmit yang menerima parameter submitted_comment. handleCommentSubmit ini memasukkan variable submitted_comment ke array comments_arr. Konten comment yang di submitted_comment dan yang di object data itu sebenarnya sama karena sama-sama mengambil event.target.comment.value.  Yang berbeda adalah property tambahan lainnya. Property di submitted_comment lebih banyak, yaitu ada cid, author, date_created. Mungkin ini bakal dipakai dalam perlakuan lainnya terhadap comments_arr.

Selanjutnya ada function handleUpdate yang menerima parameter evnet dan cid. Pertama ada panggilan preventDefault untuk mencegah refresh. Lalu ada console.log event dan cid. Lalu ada variable comment yang menampung value comment yang sedang diupdate. Ada variable comment_id yang menampung cid. Ada variable post_id yang menampung post_id dari statelocal. Ada variable user_id yang menampung nilai uid dari database. Ada variable username menampung value username dari database. Ada boolean isEdited yang di-set ke true. Ada variable yang menampung String Just Now. Ada object edited_comment yang propertynya adalah cid, comment, user_id, author, date_created, isEdited. Ada juga object data yang memiliki property cid comment, post_id, user_id, username. Ini sepertinya serupa dengan object di dalam function handleSubmit di atas. Yang di bawa ke database lewat function axios adalah object data. Sementara object edited_comment diteruskan ke comments_arr melalui function handleCommentUpdate.

Selanjutnya ada funcion handleDeleteComment yang menerima parameter cid. Pertama ada variable comment_id yang menerima value cid. Lalu data cid tadi diteruskan ke route delete/comment lewat functio axios.delete ke database untuk menghapus database dengan comment_id tersebut. Selanjutnya cid diteruskan ke function handleCommentDelete untuk menghapus comment dengan cid tersebut dari comments_arr. Sepertinya comments arr ini bakal dipakai di function tambahan lain di frontend seperti misalnya untuk pagination dan tampilan di laman. Kalau function tambahan lain ini mesti memanggil ke database sepertinya bakal tidak efisien. Jadi mungki lebih baik datanya disimpan sementara di server dengan array tadi.
Function terakhir di sini adalah handleLikes yang tidak menerima parameter. Di sini ada variable user_id yang menampung data uid dari database. Lalu ada variable post_id menampung data post_id dari stateLocal. Ada object data yang propertynya adalah uid dan post_id tadi. Lalu ada function axios.put yang meneruskan object data lalu diteruskan dengan ternary. Di ternary ini diperiksa 2 statement yang agak kompleks. Statement pertama adalah apakah di dalam property like_user_ids di dalam stateLocal  ada variable user_id, ini mungkin artinya apakah di dalam data orang-orang yang me-like post tersebut sudah ada user yang saat ini akan me-like post ini. Statement kedua adalah apakah di dalam stateLocal ada property like_post, ini mungkin artinya apakah post tersebut sudah di-like atau belum. Jika kedua statement tersebut true, maka state di dalam stateLocal akan diubah propertynya, yaitu property likes ditambah satu dan like_post diubah jadi false. Perihal like_post ini mesti dicek lagi, mungkin dia berbeda dari yang saya tulis sebelumnya. Jika kedua statement tersebut tidak true, maka akan return null.
Sepertinya bagian showPost ini lebih kompleks karena element commentsnya.

Jadi pemakaian beberapa useEffects di atas sebagian adalah untuk membedakan panggilan ke laman post dari forum atau dari sumber eksternal. Jika diambil dari forum, maka ada sebagian data yang masih tersimpan di state di react router, yaitu di elemen Link. Kita bisa memakai data di situ melalui pemakaian props, jadi kita tidak perlu memakai panggilan API ke database. Ini mungkin bisa menghemat memory. Untuk panggilan ke laman melalui URL langsung, kita memakai cara ekstraksi pathname dari link, yang kemudian kita pakai dalam panggilan API ke database.
Styling untuk komentar ada di bagian App.css di folder src di Client. Tapi entah kenapa ini tidak di-import di showpost walaupun dipakai di situ.

Comments