You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ms/7-bank-project/4-state-management/README.md

16 KiB

Bina Aplikasi Perbankan Bahagian 4: Konsep Pengurusan Keadaan

Kuiz Pra-Kuliah

Kuiz pra-kuliah

Pengenalan

Apabila aplikasi web berkembang, ia menjadi cabaran untuk menjejaki semua aliran data. Kod mana yang mendapatkan data, halaman mana yang menggunakannya, di mana dan bila ia perlu dikemas kini...mudah untuk berakhir dengan kod yang berselerak dan sukar untuk diselenggara. Ini terutamanya benar apabila anda perlu berkongsi data antara halaman yang berbeza dalam aplikasi anda, contohnya data pengguna. Konsep pengurusan keadaan sentiasa wujud dalam semua jenis program, tetapi apabila aplikasi web terus berkembang dalam kerumitan, ia kini menjadi titik utama untuk difikirkan semasa pembangunan.

Dalam bahagian terakhir ini, kita akan melihat semula aplikasi yang telah kita bina untuk memikirkan semula bagaimana keadaan diuruskan, membolehkan sokongan untuk penyegaran pelayar pada bila-bila masa, dan mengekalkan data merentasi sesi pengguna.

Prasyarat

Anda perlu telah melengkapkan bahagian pengambilan data aplikasi web untuk pelajaran ini. Anda juga perlu memasang Node.js dan menjalankan API pelayan secara tempatan supaya anda boleh menguruskan data akaun.

Anda boleh menguji bahawa pelayan berjalan dengan betul dengan melaksanakan arahan ini dalam terminal:

curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result

Memikirkan semula pengurusan keadaan

Dalam pelajaran sebelumnya, kami memperkenalkan konsep asas keadaan dalam aplikasi kami dengan pembolehubah global account yang mengandungi data bank untuk pengguna yang sedang log masuk. Walau bagaimanapun, pelaksanaan semasa kami mempunyai beberapa kelemahan. Cuba segarkan halaman apabila anda berada di papan pemuka. Apa yang berlaku?

Terdapat 3 isu dengan kod semasa:

  • Keadaan tidak dikekalkan, kerana penyegaran pelayar membawa anda kembali ke halaman log masuk.
  • Terdapat pelbagai fungsi yang mengubah keadaan. Apabila aplikasi berkembang, ia boleh menyukarkan untuk menjejaki perubahan dan mudah untuk terlupa mengemas kini satu.
  • Keadaan tidak dibersihkan, jadi apabila anda klik pada Logout, data akaun masih ada walaupun anda berada di halaman log masuk.

Kami boleh mengemas kini kod kami untuk menangani isu-isu ini satu persatu, tetapi ia akan mencipta lebih banyak penduaan kod dan menjadikan aplikasi lebih kompleks dan sukar untuk diselenggara. Atau kami boleh berhenti seketika dan memikirkan semula strategi kami.

Apakah masalah yang sebenarnya kita cuba selesaikan di sini?

Pengurusan keadaan adalah tentang mencari pendekatan yang baik untuk menyelesaikan dua masalah tertentu ini:

  • Bagaimana untuk memastikan aliran data dalam aplikasi mudah difahami?
  • Bagaimana untuk memastikan data keadaan sentiasa selaras dengan antara muka pengguna (dan sebaliknya)?

Setelah anda menjaga perkara ini, sebarang isu lain yang mungkin anda hadapi mungkin telah diselesaikan atau menjadi lebih mudah untuk diperbaiki. Terdapat banyak pendekatan yang mungkin untuk menyelesaikan masalah ini, tetapi kami akan menggunakan penyelesaian biasa yang terdiri daripada memusatkan data dan cara untuk mengubahnya. Aliran data akan berjalan seperti ini:

Skema menunjukkan aliran data antara HTML, tindakan pengguna dan keadaan

Kami tidak akan membincangkan di sini bahagian di mana data secara automatik mencetuskan kemas kini paparan, kerana ia berkaitan dengan konsep yang lebih maju dalam Pengaturcaraan Reaktif. Ia adalah subjek susulan yang baik jika anda ingin mendalami.

Terdapat banyak perpustakaan di luar sana dengan pendekatan yang berbeza untuk pengurusan keadaan, Redux menjadi pilihan yang popular. Lihat konsep dan corak yang digunakan kerana ia sering menjadi cara yang baik untuk belajar tentang isu-isu yang mungkin anda hadapi dalam aplikasi web besar dan bagaimana ia boleh diselesaikan.

Tugasan

Kami akan bermula dengan sedikit penstrukturan semula. Gantikan deklarasi account:

let account = null;

Dengan:

let state = {
  account: null
};

Idea di sini adalah untuk memusatkan semua data aplikasi kami dalam satu objek keadaan. Kami hanya mempunyai account buat masa ini dalam keadaan jadi ia tidak banyak berubah, tetapi ia mencipta laluan untuk evolusi.

Kami juga perlu mengemas kini fungsi yang menggunakannya. Dalam fungsi register() dan login(), gantikan account = ... dengan state.account = ...;

Di bahagian atas fungsi updateDashboard(), tambahkan baris ini:

const account = state.account;

Penstrukturan semula ini sendiri tidak membawa banyak peningkatan, tetapi idea di sini adalah untuk meletakkan asas untuk perubahan seterusnya.

Menjejaki perubahan data

Sekarang kita telah meletakkan objek state untuk menyimpan data kita, langkah seterusnya adalah untuk memusatkan kemas kini. Matlamatnya adalah untuk memudahkan menjejaki sebarang perubahan dan bila ia berlaku.

Untuk mengelakkan perubahan dibuat pada objek state, adalah juga amalan yang baik untuk menganggapnya tidak boleh diubah, yang bermaksud ia tidak boleh diubah sama sekali. Ini juga bermaksud anda perlu mencipta objek keadaan baharu jika anda ingin mengubah apa-apa di dalamnya. Dengan melakukan ini, anda membina perlindungan terhadap kesan sampingan yang berpotensi tidak diingini, dan membuka kemungkinan untuk ciri baharu dalam aplikasi anda seperti melaksanakan undo/redo, sambil juga memudahkan penyahpepijatan. Sebagai contoh, anda boleh log setiap perubahan yang dibuat pada keadaan dan menyimpan sejarah perubahan untuk memahami punca pepijat.

Dalam JavaScript, anda boleh menggunakan Object.freeze() untuk mencipta versi tidak boleh diubah bagi objek. Jika anda cuba membuat perubahan pada objek tidak boleh diubah, pengecualian akan dinaikkan.

Adakah anda tahu perbezaan antara objek tidak boleh diubah shallow dan deep? Anda boleh membacanya di sini.

Tugasan

Mari kita cipta fungsi baharu updateState():

function updateState(property, newData) {
  state = Object.freeze({
    ...state,
    [property]: newData
  });
}

Dalam fungsi ini, kami mencipta objek keadaan baharu dan menyalin data daripada keadaan sebelumnya menggunakan operator spread (...). Kemudian kami menimpa sifat tertentu objek keadaan dengan data baharu menggunakan notasi kurungan [property] untuk tugasan. Akhirnya, kami mengunci objek untuk mengelakkan pengubahsuaian menggunakan Object.freeze(). Buat masa ini, kami hanya mempunyai sifat account yang disimpan dalam keadaan, tetapi dengan pendekatan ini anda boleh menambah sebanyak mana sifat yang anda perlukan dalam keadaan.

Kami juga akan mengemas kini inisialisasi state untuk memastikan keadaan awal juga dibekukan:

let state = Object.freeze({
  account: null
});

Selepas itu, kemas kini fungsi register dengan menggantikan tugasan state.account = result; dengan:

updateState('account', result);

Lakukan perkara yang sama dengan fungsi login, menggantikan state.account = data; dengan:

updateState('account', data);

Kami kini akan mengambil peluang untuk membetulkan isu data akaun yang tidak dibersihkan apabila pengguna klik pada Logout.

Cipta fungsi baharu logout():

function logout() {
  updateState('account', null);
  navigate('/login');
}

Dalam updateDashboard(), gantikan pengalihan return navigate('/login'); dengan return logout();

Cuba daftar akaun baharu, log keluar dan log masuk semula untuk memastikan semuanya masih berfungsi dengan betul.

Petua: anda boleh melihat semua perubahan keadaan dengan menambahkan console.log(state) di bahagian bawah updateState() dan membuka konsol dalam alat pembangunan pelayar anda.

Mengekalkan keadaan

Kebanyakan aplikasi web perlu mengekalkan data untuk dapat berfungsi dengan betul. Semua data kritikal biasanya disimpan dalam pangkalan data dan diakses melalui API pelayan, seperti data akaun pengguna dalam kes kami. Tetapi kadang-kadang, ia juga menarik untuk mengekalkan beberapa data pada aplikasi klien yang berjalan dalam pelayar anda, untuk pengalaman pengguna yang lebih baik atau untuk meningkatkan prestasi pemuatan.

Apabila anda ingin mengekalkan data dalam pelayar anda, terdapat beberapa soalan penting yang harus anda tanyakan kepada diri sendiri:

  • Adakah data itu sensitif? Anda harus mengelakkan menyimpan sebarang data sensitif pada klien, seperti kata laluan pengguna.
  • Berapa lama anda perlu menyimpan data ini? Adakah anda merancang untuk mengakses data ini hanya untuk sesi semasa atau adakah anda mahu ia disimpan selama-lamanya?

Terdapat pelbagai cara untuk menyimpan maklumat dalam aplikasi web, bergantung pada apa yang anda ingin capai. Sebagai contoh, anda boleh menggunakan URL untuk menyimpan pertanyaan carian, dan menjadikannya boleh dikongsi antara pengguna. Anda juga boleh menggunakan HTTP cookies jika data perlu dikongsi dengan pelayan, seperti maklumat pengesahan.

Pilihan lain adalah menggunakan salah satu daripada banyak API pelayar untuk menyimpan data. Dua daripadanya sangat menarik:

  • localStorage: sebuah Key/Value store yang membolehkan untuk mengekalkan data khusus untuk laman web semasa merentasi sesi yang berbeza. Data yang disimpan di dalamnya tidak pernah tamat tempoh.
  • sessionStorage: ini berfungsi sama seperti localStorage kecuali data yang disimpan di dalamnya akan dibersihkan apabila sesi tamat (apabila pelayar ditutup).

Perhatikan bahawa kedua-dua API ini hanya membenarkan untuk menyimpan strings. Jika anda ingin menyimpan objek kompleks, anda perlu menyusunnya ke format JSON menggunakan JSON.stringify().

Jika anda ingin mencipta aplikasi web yang tidak berfungsi dengan pelayan, adalah juga mungkin untuk mencipta pangkalan data pada klien menggunakan API IndexedDB. Ini adalah untuk kes penggunaan yang lebih maju atau jika anda perlu menyimpan sejumlah besar data, kerana ia lebih kompleks untuk digunakan.

Tugasan

Kami mahu pengguna kami kekal log masuk sehingga mereka secara eksplisit klik pada butang Logout, jadi kami akan menggunakan localStorage untuk menyimpan data akaun. 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 akaun pengguna akan dikekalkan dan sentiasa terkini kerana kami telah memusatkan semua kemas kini keadaan kami sebelum ini. Di sinilah kami mula mendapat manfaat daripada semua penstrukturan semula kami sebelum ini 🙂.

Oleh kerana data disimpan, kami juga perlu mengambil berat tentang memulihkannya apabila aplikasi dimuatkan. Oleh kerana kami akan mula mempunyai lebih banyak kod inisialisasi, mungkin idea yang baik untuk mencipta fungsi baharu init, yang juga termasuk kod kami sebelum ini di bahagian 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 mengemas kini keadaan sewajarnya. Adalah penting untuk melakukan ini sebelum mengemas kini laluan, kerana mungkin terdapat kod yang bergantung pada keadaan semasa kemas kini halaman.

Kami juga boleh menjadikan halaman Dashboard sebagai halaman lalai aplikasi kami, kerana kami kini mengekalkan data akaun. Jika tiada data ditemui, papan pemuka akan menguruskan pengalihan ke halaman Login pula. Dalam updateRoute(), gantikan fallback return navigate('/login'); dengan return navigate('/dashboard');.

Sekarang log masuk ke aplikasi dan cuba segarkan halaman. Anda sepatutnya kekal di papan pemuka. Dengan kemas kini itu, kami telah menjaga semua isu awal kami...

Segarkan data

...Tetapi kami mungkin juga telah mencipta isu baharu. Oops!

Pergi ke papan pemuka menggunakan akaun test, kemudian jalankan arahan ini pada terminal untuk mencipta transaksi baharu:

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

Cuba segarkan halaman papan pemuka anda dalam pelayar sekarang. Apa yang berlaku? Adakah anda melihat transaksi baharu?

Keadaan dikekalkan selama-lamanya terima kasih kepada localStorage, tetapi itu juga bermaksud ia tidak pernah dikemas kini sehingga anda log keluar dari aplikasi dan log masuk semula!

Satu strategi yang mungkin untuk membetulkan itu adalah dengan memuat semula data akaun setiap kali papan pemuka dimuatkan, untuk mengelakkan data yang tidak terkini.

Tugasan

Cipta fungsi baharu 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);
}

Kaedah ini memeriksa bahawa kami sedang log masuk kemudian memuat semula data akaun dari pelayan.

Cipta satu lagi fungsi bernama refresh:

async function refresh() {
  await updateAccountData();
  updateDashboard();
}

Yang ini mengemas kini data akaun, kemudian menguruskan mengemas kini HTML halaman papan pemuka. Inilah yang perlu kita panggil apabila laluan papan pemuka dimuatkan. Kemas kini definisi laluan dengan:

const routes = {
  '/login': { templateId: 'login' },
  '/dashboard': { templateId: 'dashboard', init: refresh }
};

Cuba muat semula papan pemuka sekarang, ia sepatutnya memaparkan data akaun yang dikemas kini.


🚀 Cabaran

Sekarang kita memuat semula data akaun setiap kali papan pemuka dimuatkan, adakah anda fikir kita masih perlu mengekalkan semua data akaun?

Cuba bekerjasama untuk mengubah apa yang disimpan dan dimuatkan dari localStorage untuk hanya memasukkan apa yang benar-benar diperlukan untuk aplikasi berfungsi.

Kuiz Pasca-Kuliah

Kuiz selepas kuliah

Tugasan

Laksanakan dialog "Tambah transaksi"

Berikut adalah contoh hasil selepas menyelesaikan tugasan:

Tangkap layar menunjukkan contoh dialog "Tambah transaksi"


Penafian:
Dokumen ini telah diterjemahkan menggunakan perkhidmatan terjemahan AI Co-op Translator. Walaupun kami berusaha untuk memastikan ketepatan, sila ambil perhatian bahawa terjemahan automatik mungkin mengandungi kesilapan atau ketidaktepatan. Dokumen asal dalam bahasa asalnya harus dianggap sebagai sumber yang berwibawa. Untuk maklumat yang kritikal, terjemahan manusia profesional adalah disyorkan. Kami tidak bertanggungjawab atas sebarang salah faham atau salah tafsir yang timbul daripada penggunaan terjemahan ini.