|
|
2 months ago | |
|---|---|---|
| .. | ||
| README.md | 2 months ago | |
| assignment.md | 3 months ago | |
README.md
Membangun Aplikasi Perbankan Bagian 4: Konsep Manajemen State
Kuis Pra-Pelajaran
Pendahuluan
Seiring dengan berkembangnya aplikasi web, menjadi tantangan untuk melacak semua aliran data. Kode mana yang mendapatkan data, halaman mana yang menggunakannya, di mana dan kapan data perlu diperbarui...mudah sekali berakhir dengan kode yang berantakan dan sulit untuk dikelola. Hal ini terutama berlaku ketika Anda perlu berbagi data di antara berbagai halaman aplikasi Anda, misalnya data pengguna. Konsep manajemen state selalu ada di semua jenis program, tetapi karena aplikasi web terus berkembang dalam kompleksitas, sekarang menjadi poin penting untuk dipikirkan selama pengembangan.
Dalam bagian terakhir ini, kita akan meninjau kembali aplikasi yang telah kita bangun untuk memikirkan ulang bagaimana state dikelola, memungkinkan dukungan untuk penyegaran browser kapan saja, dan mempertahankan data di antara sesi pengguna.
Prasyarat
Anda perlu menyelesaikan bagian pengambilan data dari aplikasi web untuk pelajaran ini. Anda juga perlu menginstal Node.js dan menjalankan server API secara lokal sehingga Anda dapat mengelola data akun.
Anda dapat menguji apakah server berjalan dengan baik dengan menjalankan perintah ini di terminal:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
Memikirkan ulang manajemen state
Dalam pelajaran sebelumnya, kami memperkenalkan konsep dasar state dalam aplikasi kami dengan variabel global account yang berisi data bank untuk pengguna yang sedang masuk. Namun, implementasi kami saat ini memiliki beberapa kekurangan. Coba segarkan halaman saat Anda berada di dashboard. Apa yang terjadi?
Ada 3 masalah dengan kode saat ini:
- State tidak dipertahankan, karena penyegaran browser membawa Anda kembali ke halaman login.
- Ada beberapa fungsi yang memodifikasi state. Seiring dengan berkembangnya aplikasi, hal ini dapat membuat perubahan sulit dilacak dan mudah lupa untuk memperbarui salah satunya.
- State tidak dibersihkan, sehingga ketika Anda mengklik Logout, data akun masih ada meskipun Anda berada di halaman login.
Kami dapat memperbarui kode kami untuk mengatasi masalah ini satu per satu, tetapi itu akan menciptakan lebih banyak duplikasi kode dan membuat aplikasi lebih kompleks serta sulit untuk dikelola. Atau kami dapat berhenti sejenak dan memikirkan ulang strategi kami.
Masalah apa yang sebenarnya kita coba selesaikan di sini?
Manajemen state adalah tentang menemukan pendekatan yang baik untuk menyelesaikan dua masalah khusus ini:
- Bagaimana cara menjaga aliran data dalam aplikasi tetap dapat dipahami?
- Bagaimana cara menjaga data state selalu sinkron dengan antarmuka pengguna (dan sebaliknya)?
Setelah Anda mengatasi masalah ini, masalah lain yang mungkin Anda miliki mungkin sudah teratasi atau menjadi lebih mudah untuk diperbaiki. Ada banyak pendekatan yang mungkin untuk menyelesaikan masalah ini, tetapi kami akan menggunakan solusi umum yang terdiri dari memusatkan data dan cara untuk mengubahnya. Aliran data akan berjalan seperti ini:
Di sini kami tidak akan membahas bagian di mana data secara otomatis memicu pembaruan tampilan, karena itu terkait dengan konsep yang lebih maju dari Pemrograman Reaktif. Ini adalah subjek lanjutan yang bagus jika Anda ingin mendalami lebih jauh.
✅ Ada banyak pustaka di luar sana dengan pendekatan berbeda untuk manajemen state, Redux menjadi salah satu opsi populer. Lihatlah konsep dan pola yang digunakan karena sering kali merupakan cara yang baik untuk mempelajari potensi masalah yang mungkin Anda hadapi dalam aplikasi web besar dan bagaimana cara menyelesaikannya.
Tugas
Kita akan mulai dengan sedikit refaktor. Ganti deklarasi account:
let account = null;
Dengan:
let state = {
account: null
};
Idenya adalah untuk memusatkan semua data aplikasi kami dalam satu objek state. Saat ini kami hanya memiliki account dalam state sehingga tidak banyak berubah, tetapi ini menciptakan jalur untuk evolusi.
Kami juga harus memperbarui fungsi yang menggunakannya. Dalam fungsi register() dan login(), ganti account = ... dengan state.account = ...;
Di bagian atas fungsi updateDashboard(), tambahkan baris ini:
const account = state.account;
Refaktor ini sendiri tidak membawa banyak peningkatan, tetapi idenya adalah untuk meletakkan dasar bagi perubahan berikutnya.
Melacak perubahan data
Sekarang setelah kami menempatkan objek state untuk menyimpan data kami, langkah berikutnya adalah memusatkan pembaruan. Tujuannya adalah untuk mempermudah melacak setiap perubahan dan kapan perubahan itu terjadi.
Untuk menghindari perubahan yang dilakukan pada objek state, juga merupakan praktik yang baik untuk menganggapnya immutable, yang berarti bahwa objek tersebut tidak dapat dimodifikasi sama sekali. Ini juga berarti bahwa Anda harus membuat objek state baru jika Anda ingin mengubah apa pun di dalamnya. Dengan melakukan ini, Anda membangun perlindungan terhadap efek samping yang mungkin tidak diinginkan, dan membuka kemungkinan untuk fitur baru dalam aplikasi Anda seperti menerapkan undo/redo, sambil juga mempermudah debugging. Misalnya, Anda dapat mencatat setiap perubahan yang dilakukan pada state dan menyimpan riwayat perubahan untuk memahami sumber bug.
Dalam JavaScript, Anda dapat menggunakan Object.freeze() untuk membuat versi objek yang tidak dapat diubah. Jika Anda mencoba membuat perubahan pada objek yang tidak dapat diubah, sebuah pengecualian akan muncul.
✅ Apakah Anda tahu perbedaan antara objek shallow dan deep yang tidak dapat diubah? Anda dapat membacanya di sini.
Tugas
Mari kita buat fungsi baru updateState():
function updateState(property, newData) {
state = Object.freeze({
...state,
[property]: newData
});
}
Dalam fungsi ini, kami membuat objek state baru dan menyalin data dari state sebelumnya menggunakan operator spread (...). Kemudian kami menimpa properti tertentu dari objek state dengan data baru menggunakan notasi kurung [property] untuk penugasan. Akhirnya, kami mengunci objek untuk mencegah modifikasi menggunakan Object.freeze(). Saat ini kami hanya memiliki properti account yang disimpan dalam state, tetapi dengan pendekatan ini Anda dapat menambahkan sebanyak mungkin properti yang Anda butuhkan dalam state.
Kami juga akan memperbarui inisialisasi state untuk memastikan state awal juga dibekukan:
let state = Object.freeze({
account: null
});
Setelah itu, perbarui fungsi register dengan mengganti penugasan state.account = result; dengan:
updateState('account', result);
Lakukan hal yang sama dengan fungsi login, mengganti state.account = data; dengan:
updateState('account', data);
Kami sekarang akan mengambil kesempatan untuk memperbaiki masalah data akun yang tidak dibersihkan ketika pengguna mengklik Logout.
Buat fungsi baru logout():
function logout() {
updateState('account', null);
navigate('/login');
}
Dalam updateDashboard(), ganti pengalihan return navigate('/login'); dengan return logout();
Cobalah mendaftarkan akun baru, keluar, dan masuk lagi untuk memeriksa apakah semuanya masih berfungsi dengan benar.
Tip: Anda dapat melihat semua perubahan state dengan menambahkan
console.log(state)di bagian bawahupdateState()dan membuka konsol di alat pengembangan browser Anda.
Mempertahankan state
Sebagian besar aplikasi web perlu mempertahankan data agar dapat berfungsi dengan benar. Semua data penting biasanya disimpan di database dan diakses melalui server API, seperti data akun pengguna dalam kasus kami. Tetapi terkadang, juga menarik untuk mempertahankan beberapa data di aplikasi klien yang berjalan di browser Anda, untuk pengalaman pengguna yang lebih baik atau untuk meningkatkan kinerja pemuatan.
Ketika Anda ingin mempertahankan data di browser Anda, ada beberapa pertanyaan penting yang harus Anda tanyakan pada diri sendiri:
- Apakah data ini sensitif? Anda harus menghindari menyimpan data sensitif di klien, seperti kata sandi pengguna.
- Berapa lama Anda perlu menyimpan data ini? Apakah Anda berencana mengakses data ini hanya untuk sesi saat ini atau Anda ingin menyimpannya selamanya?
Ada beberapa cara untuk menyimpan informasi di dalam aplikasi web, tergantung pada apa yang ingin Anda capai. Misalnya, Anda dapat menggunakan URL untuk menyimpan kueri pencarian, dan membuatnya dapat dibagikan antara pengguna. Anda juga dapat menggunakan HTTP cookies jika data perlu dibagikan dengan server, seperti informasi autentikasi.
Opsi lain adalah menggunakan salah satu dari banyak API browser untuk menyimpan data. Dua di antaranya sangat menarik:
localStorage: sebuah Key/Value store yang memungkinkan untuk mempertahankan data spesifik untuk situs web saat ini di antara sesi yang berbeda. Data yang disimpan di dalamnya tidak pernah kedaluwarsa.sessionStorage: yang satu ini bekerja sama sepertilocalStoragekecuali bahwa data yang disimpan di dalamnya dihapus saat sesi berakhir (saat browser ditutup).
Perlu dicatat bahwa kedua API ini hanya memungkinkan untuk menyimpan string. Jika Anda ingin menyimpan objek kompleks, Anda perlu menyerialkannya ke format JSON menggunakan JSON.stringify().
✅ Jika Anda ingin membuat aplikasi web yang tidak bekerja dengan server, juga memungkinkan untuk membuat database di klien menggunakan API IndexedDB. Yang satu ini disediakan untuk kasus penggunaan lanjutan atau jika Anda perlu menyimpan sejumlah besar data, karena lebih kompleks untuk digunakan.
Tugas
Kami ingin pengguna kami tetap masuk hingga mereka secara eksplisit mengklik tombol Logout, jadi kami akan menggunakan localStorage untuk menyimpan data akun. Pertama, mari kita tentukan kunci yang akan kita gunakan untuk menyimpan data kita.
const storageKey = 'savedAccount';
Kemudian tambahkan baris ini di akhir fungsi updateState():
localStorage.setItem(storageKey, JSON.stringify(state.account));
Dengan ini, data akun pengguna akan dipertahankan dan selalu diperbarui karena sebelumnya kami memusatkan semua pembaruan state kami. Di sinilah kami mulai mendapatkan manfaat dari semua refaktor sebelumnya 🙂.
Karena data disimpan, kami juga harus mengurus pemulihannya saat aplikasi dimuat. Karena kami akan mulai memiliki lebih banyak kode inisialisasi, mungkin ide yang baik untuk membuat fungsi baru init, yang juga mencakup kode sebelumnya di bagian bawah app.js:
function init() {
const savedAccount = localStorage.getItem(storageKey);
if (savedAccount) {
updateState('account', JSON.parse(savedAccount));
}
// Our previous initialization code
window.onpopstate = () => updateRoute();
updateRoute();
}
init();
Di sini kami mengambil data yang disimpan, dan jika ada, kami memperbarui state sesuai. Penting untuk melakukan ini sebelum memperbarui rute, karena mungkin ada kode yang bergantung pada state selama pembaruan halaman.
Kami juga dapat menjadikan halaman Dashboard sebagai halaman default aplikasi kami, karena sekarang kami mempertahankan data akun. Jika tidak ada data yang ditemukan, dashboard akan mengurus pengalihan ke halaman Login bagaimanapun. Dalam updateRoute(), ganti fallback return navigate('/login'); dengan return navigate('/dashboard');.
Sekarang masuk ke aplikasi dan coba segarkan halaman. Anda seharusnya tetap berada di dashboard. Dengan pembaruan itu kami telah mengatasi semua masalah awal kami...
Menyegarkan data
...Tetapi kami mungkin juga telah menciptakan masalah baru. Ups!
Pergi ke dashboard menggunakan akun test, lalu jalankan perintah ini di terminal untuk membuat transaksi baru:
curl --request POST \
--header "Content-Type: application/json" \
--data "{ \"date\": \"2020-07-24\", \"object\": \"Bought book\", \"amount\": -20 }" \
http://localhost:5000/api/accounts/test/transactions
Coba segarkan halaman dashboard Anda di browser sekarang. Apa yang terjadi? Apakah Anda melihat transaksi baru?
State dipertahankan tanpa batas waktu berkat localStorage, tetapi itu juga berarti tidak pernah diperbarui hingga Anda keluar dari aplikasi dan masuk lagi!
Salah satu strategi yang mungkin untuk memperbaikinya adalah memuat ulang data akun setiap kali dashboard dimuat, untuk menghindari data yang tidak diperbarui.
Tugas
Buat fungsi baru updateAccountData:
async function updateAccountData() {
const account = state.account;
if (!account) {
return logout();
}
const data = await getAccount(account.user);
if (data.error) {
return logout();
}
updateState('account', data);
}
Metode ini memeriksa bahwa kami saat ini masuk lalu memuat ulang data akun dari server.
Buat fungsi lain bernama refresh:
async function refresh() {
await updateAccountData();
updateDashboard();
}
Yang satu ini memperbarui data akun, lalu mengurus pembaruan HTML halaman dashboard. Ini adalah apa yang perlu kita panggil saat rute dashboard dimuat. Perbarui definisi rute dengan:
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: refresh }
};
Coba muat ulang dashboard sekarang, seharusnya menampilkan data akun yang diperbarui.
🚀 Tantangan
Sekarang setelah kami memuat ulang data akun setiap kali dashboard dimuat, apakah menurut Anda kami masih perlu mempertahankan semua data akun?
Cobalah bekerja sama untuk mengubah apa yang disimpan dan dimuat dari localStorage agar hanya mencakup apa yang benar-benar diperlukan untuk aplikasi berfungsi.
Kuis Pasca-Pelajaran
Tugas
Implementasikan dialog "Tambah transaksi"
Berikut adalah contoh hasil setelah menyelesaikan tugas:
Penafian:
Dokumen ini telah diterjemahkan menggunakan layanan terjemahan AI Co-op Translator. Meskipun kami berupaya untuk memberikan hasil yang akurat, harap diperhatikan bahwa terjemahan otomatis mungkin mengandung kesalahan atau ketidakakuratan. Dokumen asli dalam bahasa aslinya harus dianggap sebagai sumber yang berwenang. Untuk informasi yang bersifat kritis, disarankan menggunakan jasa penerjemah manusia profesional. Kami tidak bertanggung jawab atas kesalahpahaman atau penafsiran yang keliru yang timbul dari penggunaan terjemahan ini.

