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/th/7-bank-project/4-state-management/README.md

500 lines
52 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "32bd800759c3e943c38ad9ae6e1f51e0",
"translation_date": "2025-10-23T21:07:24+00:00",
"source_file": "7-bank-project/4-state-management/README.md",
"language_code": "th"
}
-->
# สร้างแอปธนาคาร ตอนที่ 4: แนวคิดการจัดการสถานะ
## แบบทดสอบก่อนเรียน
[แบบทดสอบก่อนเรียน](https://ff-quizzes.netlify.app/web/quiz/47)
## บทนำ
การจัดการสถานะเปรียบเสมือนระบบนำทางบนยาน Voyager เมื่อทุกอย่างทำงานได้อย่างราบรื่น คุณแทบจะไม่รู้สึกถึงการมีอยู่ของมัน แต่เมื่อเกิดปัญหา มันจะกลายเป็นตัวแปรสำคัญที่ทำให้ยานไปถึงอวกาศระหว่างดวงดาวหรือหลงทางในอวกาศ ในการพัฒนาเว็บ สถานะหมายถึงทุกสิ่งที่แอปพลิเคชันของคุณต้องจดจำ เช่น สถานะการเข้าสู่ระบบของผู้ใช้ ข้อมูลในฟอร์ม ประวัติการนำทาง และสถานะชั่วคราวของอินเทอร์เฟซ
เมื่อแอปธนาคารของคุณพัฒนาจากฟอร์มเข้าสู่ระบบแบบง่าย ๆ ไปเป็นแอปพลิเคชันที่ซับซ้อนมากขึ้น คุณอาจพบกับความท้าทายทั่วไป เช่น การรีเฟรชหน้าแล้วผู้ใช้ถูกออกจากระบบโดยไม่คาดคิด การปิดเบราว์เซอร์แล้วความคืบหน้าทั้งหมดหายไป หรือการแก้ไขปัญหาโดยต้องค้นหาผ่านฟังก์ชันหลาย ๆ ตัวที่แก้ไขข้อมูลเดียวกันในวิธีที่ต่างกัน
นี่ไม่ใช่สัญญาณของการเขียนโค้ดที่ไม่ดี แต่เป็นความเจ็บปวดที่เกิดขึ้นตามธรรมชาติเมื่อแอปพลิเคชันมีความซับซ้อนถึงระดับหนึ่ง นักพัฒนาทุกคนต้องเผชิญกับความท้าทายเหล่านี้เมื่อแอปพลิเคชันเปลี่ยนจาก "การพิสูจน์แนวคิด" ไปเป็น "พร้อมใช้งานจริง"
ในบทเรียนนี้ เราจะนำระบบการจัดการสถานะที่เป็นศูนย์กลางมาใช้เพื่อเปลี่ยนแอปธนาคารของคุณให้เป็นแอปพลิเคชันที่เชื่อถือได้และเป็นมืออาชีพ คุณจะได้เรียนรู้วิธีจัดการการไหลของข้อมูลอย่างคาดการณ์ได้ รักษาสถานะการเข้าสู่ระบบของผู้ใช้อย่างเหมาะสม และสร้างประสบการณ์ผู้ใช้ที่ราบรื่นซึ่งแอปพลิเคชันเว็บสมัยใหม่ต้องการ
## ความรู้พื้นฐานที่ต้องมี
ก่อนที่จะดำดิ่งสู่แนวคิดการจัดการสถานะ คุณต้องตั้งค่าพื้นฐานการพัฒนาและมีโครงสร้างแอปธนาคารของคุณพร้อม บทเรียนนี้สร้างขึ้นจากแนวคิดและโค้ดจากส่วนก่อนหน้าของซีรีส์นี้โดยตรง
**การตั้งค่าที่จำเป็น:**
- ทำบทเรียน [การดึงข้อมูล](../3-data/README.md) ให้เสร็จสมบูรณ์ - แอปของคุณควรโหลดและแสดงข้อมูลบัญชีได้สำเร็จ
- ติดตั้ง [Node.js](https://nodejs.org) บนระบบของคุณเพื่อรัน API ฝั่งเซิร์ฟเวอร์
- เริ่มต้น [API เซิร์ฟเวอร์](../api/README.md) ในเครื่องเพื่อจัดการการดำเนินการข้อมูลบัญชี
**การทดสอบสภาพแวดล้อมของคุณ:**
ตรวจสอบว่า API เซิร์ฟเวอร์ของคุณทำงานได้อย่างถูกต้องโดยการรันคำสั่งนี้ในเทอร์มินัล:
```sh
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
```
**สิ่งที่คำสั่งนี้ทำ:**
- **ส่ง**คำขอ GET ไปยัง API เซิร์ฟเวอร์ในเครื่องของคุณ
- **ทดสอบ**การเชื่อมต่อและตรวจสอบว่าเซิร์ฟเวอร์ตอบสนอง
- **ส่งคืน**ข้อมูลเวอร์ชัน API หากทุกอย่างทำงานได้อย่างถูกต้อง
---
## การวินิจฉัยปัญหาสถานะปัจจุบัน
เหมือนกับ Sherlock Holmes ที่ตรวจสอบสถานที่เกิดเหตุ เราต้องเข้าใจว่าเกิดอะไรขึ้นในโครงสร้างปัจจุบันของเราก่อนที่เราจะสามารถแก้ปัญหาการสูญเสียสถานะผู้ใช้ได้
มาทำการทดลองง่าย ๆ ที่เผยให้เห็นความท้าทายในการจัดการสถานะ:
**🧪 ลองทดสอบการวินิจฉัยนี้:**
1. เข้าสู่ระบบแอปธนาคารของคุณและไปที่แดชบอร์ด
2. รีเฟรชหน้าเบราว์เซอร์
3. สังเกตว่าเกิดอะไรขึ้นกับสถานะการเข้าสู่ระบบของคุณ
หากคุณถูกเปลี่ยนกลับไปที่หน้าจอเข้าสู่ระบบ คุณได้ค้นพบปัญหาคลาสสิกของการคงสถานะแล้ว พฤติกรรมนี้เกิดขึ้นเพราะการใช้งานปัจจุบันของเราจัดเก็บข้อมูลผู้ใช้ในตัวแปร JavaScript ที่รีเซ็ตทุกครั้งที่โหลดหน้าใหม่
**ปัญหาการใช้งานปัจจุบัน:**
ตัวแปร `account` แบบง่ายจาก [บทเรียนก่อนหน้า](../3-data/README.md) สร้างปัญหาสำคัญสามประการที่ส่งผลต่อทั้งประสบการณ์ผู้ใช้และการดูแลรักษาโค้ด:
| ปัญหา | สาเหตุทางเทคนิค | ผลกระทบต่อผู้ใช้ |
|---------|--------|----------------|
| **การสูญเสียเซสชัน** | การรีเฟรชหน้าล้างตัวแปร JavaScript | ผู้ใช้ต้องเข้าสู่ระบบใหม่บ่อยครั้ง |
| **การอัปเดตกระจัดกระจาย** | ฟังก์ชันหลายตัวแก้ไขสถานะโดยตรง | การแก้ไขข้อบกพร่องยากขึ้นเรื่อย ๆ |
| **การล้างข้อมูลไม่สมบูรณ์** | การออกจากระบบไม่ล้างการอ้างอิงสถานะทั้งหมด | ความกังวลด้านความปลอดภัยและความเป็นส่วนตัว |
**ความท้าทายด้านสถาปัตยกรรม:**
เหมือนกับการออกแบบห้องของ Titanic ที่ดูแข็งแกร่งจนกระทั่งห้องหลายห้องถูกน้ำท่วมพร้อมกัน การแก้ไขปัญหาเหล่านี้ทีละปัญหาไม่สามารถแก้ไขปัญหาสถาปัตยกรรมพื้นฐานได้ เราต้องการโซลูชันการจัดการสถานะที่ครอบคลุม
> 💡 **เรากำลังพยายามทำอะไรที่นี่?**
[การจัดการสถานะ](https://en.wikipedia.org/wiki/State_management) เป็นเรื่องของการแก้ปริศนาสองข้อพื้นฐาน:
1. **ข้อมูลของฉันอยู่ที่ไหน?**: การติดตามว่ามีข้อมูลอะไรและมาจากไหน
2. **ทุกคนเข้าใจตรงกันหรือไม่?**: การทำให้สิ่งที่ผู้ใช้เห็นตรงกับสิ่งที่เกิดขึ้นจริง
**แผนการของเรา:**
แทนที่จะไล่ตามปัญหา เราจะสร้างระบบ **การจัดการสถานะที่เป็นศูนย์กลาง** คิดว่ามันเหมือนกับการมีคนที่จัดระเบียบได้ดีคนหนึ่งที่ดูแลเรื่องสำคัญทั้งหมด:
![แผนภาพแสดงการไหลของข้อมูลระหว่าง HTML, การกระทำของผู้ใช้ และสถานะ](../../../../translated_images/data-flow.fa2354e0908fecc89b488010dedf4871418a992edffa17e73441d257add18da4.th.png)
**การทำความเข้าใจการไหลของข้อมูลนี้:**
- **รวมศูนย์**สถานะของแอปพลิเคชันทั้งหมดในที่เดียว
- **กำหนดเส้นทาง**การเปลี่ยนแปลงสถานะทั้งหมดผ่านฟังก์ชันที่ควบคุม
- **รับรอง**ว่า UI ยังคงสอดคล้องกับสถานะปัจจุบัน
- **ให้**รูปแบบที่ชัดเจนและคาดการณ์ได้สำหรับการจัดการข้อมูล
> 💡 **ข้อมูลเชิงลึกระดับมืออาชีพ**: บทเรียนนี้มุ่งเน้นไปที่แนวคิดพื้นฐาน สำหรับแอปพลิเคชันที่ซับซ้อนมากขึ้น ไลบรารีอย่าง [Redux](https://redux.js.org) มีฟีเจอร์การจัดการสถานะที่ก้าวหน้ามากขึ้น การเข้าใจหลักการพื้นฐานเหล่านี้จะช่วยให้คุณเชี่ยวชาญไลบรารีการจัดการสถานะใด ๆ
> ⚠️ **หัวข้อขั้นสูง**: เราจะไม่ครอบคลุมการอัปเดต UI อัตโนมัติที่เกิดจากการเปลี่ยนแปลงสถานะ เนื่องจากเกี่ยวข้องกับแนวคิด [การเขียนโปรแกรมเชิงปฏิกิริยา](https://en.wikipedia.org/wiki/Reactive_programming) ถือว่าเป็นขั้นตอนต่อไปที่ยอดเยี่ยมสำหรับการเรียนรู้ของคุณ!
### งาน: รวมโครงสร้างสถานะ
มาเริ่มเปลี่ยนการจัดการสถานะที่กระจัดกระจายของเราให้เป็นระบบรวมศูนย์กัน ขั้นตอนแรกนี้เป็นการสร้างรากฐานสำหรับการปรับปรุงทั้งหมดที่จะตามมา
**ขั้นตอนที่ 1: สร้างวัตถุสถานะรวมศูนย์**
แทนที่การประกาศ `account` แบบง่าย:
```js
let account = null;
```
ด้วยวัตถุสถานะที่มีโครงสร้าง:
```js
let state = {
account: null
};
```
**เหตุผลที่การเปลี่ยนแปลงนี้สำคัญ:**
- **รวมศูนย์**ข้อมูลแอปพลิเคชันทั้งหมดในที่เดียว
- **เตรียม**โครงสร้างสำหรับการเพิ่มคุณสมบัติสถานะเพิ่มเติมในภายหลัง
- **สร้าง**ขอบเขตที่ชัดเจนระหว่างสถานะและตัวแปรอื่น ๆ
- **สร้าง**รูปแบบที่สามารถขยายได้เมื่อแอปของคุณเติบโต
**ขั้นตอนที่ 2: อัปเดตรูปแบบการเข้าถึงสถานะ**
อัปเดตฟังก์ชันของคุณให้ใช้โครงสร้างสถานะใหม่:
**ในฟังก์ชัน `register()` และ `login()`**, แทนที่:
```js
account = ...
```
ด้วย:
```js
state.account = ...
```
**ในฟังก์ชัน `updateDashboard()`**, เพิ่มบรรทัดนี้ที่ด้านบน:
```js
const account = state.account;
```
**สิ่งที่การอัปเดตเหล่านี้ทำสำเร็จ:**
- **รักษา**ฟังก์ชันการทำงานที่มีอยู่ในขณะที่ปรับปรุงโครงสร้าง
- **เตรียม**โค้ดของคุณสำหรับการจัดการสถานะที่ซับซ้อนมากขึ้น
- **สร้าง**รูปแบบที่สอดคล้องกันสำหรับการเข้าถึงข้อมูลสถานะ
- **สร้าง**รากฐานสำหรับการอัปเดตสถานะรวมศูนย์
> 💡 **หมายเหตุ**: การปรับโครงสร้างนี้ไม่ได้แก้ปัญหาของเราในทันที แต่สร้างรากฐานที่จำเป็นสำหรับการปรับปรุงที่ทรงพลังที่จะตามมา!
## การดำเนินการอัปเดตสถานะที่ควบคุม
เมื่อสถานะของเรารวมศูนย์แล้ว ขั้นตอนต่อไปคือการสร้างกลไกที่ควบคุมสำหรับการแก้ไขข้อมูล วิธีนี้ช่วยให้การเปลี่ยนแปลงสถานะสามารถคาดการณ์ได้และแก้ไขข้อบกพร่องได้ง่ายขึ้น
หลักการสำคัญคล้ายกับการควบคุมการจราจรทางอากาศ: แทนที่จะอนุญาตให้ฟังก์ชันหลายตัวแก้ไขสถานะอย่างอิสระ เราจะส่งการเปลี่ยนแปลงทั้งหมดผ่านฟังก์ชันที่ควบคุมเดียว รูปแบบนี้ให้การดูแลที่ชัดเจนว่าเมื่อใดและอย่างไรที่ข้อมูลเปลี่ยนแปลง
**การจัดการสถานะที่ไม่เปลี่ยนแปลง:**
เราจะถือว่าวัตถุ `state` ของเราเป็น [*ไม่เปลี่ยนแปลง*](https://en.wikipedia.org/wiki/Immutable_object) หมายความว่าเราจะไม่แก้ไขมันโดยตรง แต่ละการเปลี่ยนแปลงจะสร้างวัตถุสถานะใหม่พร้อมข้อมูลที่อัปเดต
แม้ว่าวิธีนี้อาจดูเหมือนไม่มีประสิทธิภาพในตอนแรกเมื่อเทียบกับการแก้ไขโดยตรง แต่มันให้ข้อดีที่สำคัญสำหรับการแก้ไขข้อบกพร่อง การทดสอบ และการรักษาความสามารถในการคาดการณ์ของแอปพลิเคชัน
**ประโยชน์ของการจัดการสถานะที่ไม่เปลี่ยนแปลง:**
| ประโยชน์ | คำอธิบาย | ผลกระทบ |
|---------|-------------|--------|
| **ความสามารถในการคาดการณ์** | การเปลี่ยนแปลงเกิดขึ้นผ่านฟังก์ชันที่ควบคุมเท่านั้น | แก้ไขข้อบกพร่องและทดสอบได้ง่ายขึ้น |
| **การติดตามประวัติ** | การเปลี่ยนแปลงสถานะแต่ละครั้งสร้างวัตถุใหม่ | รองรับฟังก์ชันย้อนกลับ/ทำซ้ำ |
| **ป้องกันผลกระทบข้างเคียง** | ไม่มีการแก้ไขโดยไม่ได้ตั้งใจ | ป้องกันข้อบกพร่องที่ไม่คาดคิด |
| **การปรับปรุงประสิทธิภาพ** | ตรวจจับได้ง่ายเมื่อสถานะเปลี่ยนแปลงจริง | รองรับการอัปเดต UI อย่างมีประสิทธิภาพ |
**การจัดการสถานะไม่เปลี่ยนแปลงใน JavaScript ด้วย `Object.freeze()`:**
JavaScript มี [`Object.freeze()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) เพื่อป้องกันการแก้ไขวัตถุ:
```js
const immutableState = Object.freeze({ account: userData });
// Any attempt to modify immutableState will throw an error
```
**การแยกย่อยสิ่งที่เกิดขึ้นที่นี่:**
- **ป้องกัน**การกำหนดค่าหรือการลบคุณสมบัติโดยตรง
- **โยน**ข้อยกเว้นหากมีการพยายามแก้ไข
- **รับรอง**ว่าการเปลี่ยนแปลงสถานะต้องผ่านฟังก์ชันที่ควบคุม
- **สร้าง**สัญญาที่ชัดเจนสำหรับวิธีการอัปเดตสถานะ
> 💡 **เจาะลึก**: เรียนรู้เกี่ยวกับความแตกต่างระหว่างวัตถุไม่เปลี่ยนแปลงแบบ *ตื้น* และ *ลึก* ใน [เอกสาร MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#What_is_shallow_freeze) การเข้าใจความแตกต่างนี้เป็นสิ่งสำคัญสำหรับโครงสร้างสถานะที่ซับซ้อน
### งาน
มาสร้างฟังก์ชัน `updateState()` ใหม่:
```js
function updateState(property, newData) {
state = Object.freeze({
...state,
[property]: newData
});
}
```
ในฟังก์ชันนี้ เรากำลังสร้างวัตถุสถานะใหม่และคัดลอกข้อมูลจากสถานะก่อนหน้าด้วย [*ตัวดำเนินการกระจาย (`...`)*](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals) จากนั้นเราจะเขียนทับคุณสมบัติเฉพาะของวัตถุสถานะด้วยข้อมูลใหม่โดยใช้ [สัญลักษณ์วงเล็บ](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Working_with_Objects#Objects_and_properties) `[property]` สำหรับการกำหนดค่า สุดท้ายเราล็อควัตถุเพื่อป้องกันการแก้ไขโดยใช้ `Object.freeze()` ตอนนี้เรามีคุณสมบัติ `account` ที่จัดเก็บในสถานะเท่านั้น แต่ด้วยวิธีนี้คุณสามารถเพิ่มคุณสมบัติได้มากเท่าที่คุณต้องการในสถานะ
เราจะอัปเดตการเริ่มต้นสถานะเพื่อให้แน่ใจว่าสถานะเริ่มต้นถูกล็อคด้วย:
```js
let state = Object.freeze({
account: null
});
```
หลังจากนั้น อัปเดตฟังก์ชัน `register` โดยแทนที่การกำหนดค่า `state.account = result;` ด้วย:
```js
updateState('account', result);
```
ทำเช่นเดียวกันกับฟังก์ชัน `login` โดยแทนที่ `state.account = data;` ด้วย:
```js
updateState('account', data);
```
เราจะใช้โอกาสนี้แก้ไขปัญหาข้อมูลบัญชีที่ไม่ได้ถูกล้างเมื่อผู้ใช้คลิก *Logout*
สร้างฟังก์ชันใหม่ `logout()`:
```js
function logout() {
updateState('account', null);
navigate('/login');
}
```
ใน `updateDashboard()`, แทนที่การเปลี่ยนเส้นทาง `return navigate('/login');` ด้วย `return logout()`;
ลองลงทะเบียนบัญชีใหม่ ออกจากระบบ และเข้าสู่ระบบอีกครั้งเพื่อตรวจสอบว่าทุกอย่างยังทำงานได้อย่างถูกต้อง
> เคล็ดลับ: คุณสามารถดูการเปลี่ยนแปลงสถานะทั้งหมดได้โดยเพิ่ม `console.log(state)` ที่ด้านล่างของ `updateState()` และเปิดคอนโซลในเครื่องมือพัฒนาเบราว์เซอร์ของคุณ
## การดำเนินการคงข้อมูล
ปัญหาการสูญเสียเซสชันที่เราระบุไว้ก่อนหน้านี้ต้องการโซลูชันการคงข้อมูลที่รักษาสถานะผู้ใช้ในเซสชันเบราว์เซอร์ โซลูชันนี้เปลี่ยนแอปพลิเคชันของเราจากประสบการณ์ชั่วคราวไปเป็นเครื่องมือที่เชื่อถือได้และเป็นมืออาชีพ
ลองพิจารณาว่านาฬิกาอะตอมรักษาเวลาได้อย่างแม่นยำแม้ในช่วงที่ไฟฟ้าดับโดยการจัดเก็บสถานะสำคัญในหน่วยความจำที่ไม่ระเหย เช่นเดียวกัน แอปพลิเคชันเว็บต้องการกลไกการจัดเก็บที่คงอยู่เพื่อรักษาข้อมูลผู้ใช้ที่สำคัญในเซสชันเบราว์เซอร์และการรีเฟรชหน้า
**คำถามเชิงกลยุทธ์สำหรับการคงข้อมูล:**
ก่อนดำเนินการคงข้อมูล ให้พิจารณาปัจจัยสำคัญเหล่านี้:
| คำถาม | บริบทแ
> 💡 **ตัวเลือกขั้นสูง**: สำหรับแอปพลิเคชันออฟไลน์ที่ซับซ้อนและมีชุดข้อมูลขนาดใหญ่ ลองใช้ [`IndexedDB` API](https://developer.mozilla.org/docs/Web/API/IndexedDB_API) ซึ่งเป็นฐานข้อมูลฝั่งไคลเอนต์ที่สมบูรณ์ แต่ต้องการการพัฒนาโค้ดที่ซับซ้อนมากขึ้น
### งาน: การจัดการข้อมูลแบบถาวรด้วย localStorage
เราจะมาทำการจัดการข้อมูลแบบถาวรเพื่อให้ผู้ใช้ยังคงล็อกอินอยู่จนกว่าพวกเขาจะออกจากระบบอย่างชัดเจน โดยเราจะใช้ `localStorage` ในการเก็บข้อมูลบัญชีระหว่างการใช้งานเบราว์เซอร์
**ขั้นตอนที่ 1: กำหนดการตั้งค่าการจัดเก็บข้อมูล**
```js
const storageKey = 'savedAccount';
```
**สิ่งที่ค่าคงที่นี้ให้:**
- **สร้าง** ตัวระบุที่สอดคล้องกันสำหรับข้อมูลที่จัดเก็บ
- **ป้องกัน** การพิมพ์ผิดในการอ้างอิงคีย์การจัดเก็บ
- **ทำให้** การเปลี่ยนคีย์การจัดเก็บง่ายขึ้นเมื่อจำเป็น
- **ปฏิบัติตาม** หลักการที่ดีที่สุดสำหรับโค้ดที่ดูแลรักษาได้ง่าย
**ขั้นตอนที่ 2: เพิ่มการจัดการข้อมูลแบบถาวรอัตโนมัติ**
เพิ่มบรรทัดนี้ในตอนท้ายของฟังก์ชัน `updateState()`:
```js
localStorage.setItem(storageKey, JSON.stringify(state.account));
```
**การอธิบายสิ่งที่เกิดขึ้น:**
- **แปลง** ออบเจ็กต์บัญชีเป็นสตริง JSON เพื่อจัดเก็บ
- **บันทึก** ข้อมูลโดยใช้คีย์การจัดเก็บที่สอดคล้องกัน
- **ดำเนินการ** โดยอัตโนมัติเมื่อเกิดการเปลี่ยนแปลงสถานะ
- **รับรอง** ว่าข้อมูลที่จัดเก็บจะสอดคล้องกับสถานะปัจจุบันเสมอ
> 💡 **ประโยชน์ด้านสถาปัตยกรรม**: เนื่องจากเราได้รวมการอัปเดตสถานะทั้งหมดไว้ใน `updateState()` การเพิ่มการจัดการข้อมูลแบบถาวรจึงใช้เพียงบรรทัดเดียว ซึ่งแสดงให้เห็นถึงพลังของการตัดสินใจด้านสถาปัตยกรรมที่ดี!
**ขั้นตอนที่ 3: คืนค่าข้อมูลเมื่อแอปพลิเคชันโหลด**
สร้างฟังก์ชันเริ่มต้นเพื่อคืนค่าข้อมูลที่บันทึกไว้:
```js
function init() {
const savedAccount = localStorage.getItem(storageKey);
if (savedAccount) {
updateState('account', JSON.parse(savedAccount));
}
// Our previous initialization code
window.onpopstate = () => updateRoute();
updateRoute();
}
init();
```
**การทำความเข้าใจกระบวนการเริ่มต้น:**
- **ดึง** ข้อมูลบัญชีที่บันทึกไว้ก่อนหน้านี้จาก localStorage
- **แปลง** สตริง JSON กลับเป็นออบเจ็กต์ JavaScript
- **อัปเดต** สถานะโดยใช้ฟังก์ชันอัปเดตที่ควบคุม
- **คืนค่า** เซสชันของผู้ใช้อัตโนมัติเมื่อโหลดหน้า
- **ดำเนินการ** ก่อนการอัปเดตเส้นทางเพื่อให้แน่ใจว่าสถานะพร้อมใช้งาน
**ขั้นตอนที่ 4: ปรับปรุงเส้นทางเริ่มต้น**
อัปเดตเส้นทางเริ่มต้นเพื่อใช้ประโยชน์จากการจัดการข้อมูลแบบถาวร:
ใน `updateRoute()` ให้แทนที่:
```js
// Replace: return navigate('/login');
return navigate('/dashboard');
```
**เหตุผลที่การเปลี่ยนแปลงนี้สมเหตุสมผล:**
- **ใช้ประโยชน์** จากระบบการจัดการข้อมูลแบบถาวรใหม่อย่างมีประสิทธิภาพ
- **อนุญาต** ให้แดชบอร์ดจัดการการตรวจสอบสิทธิ์
- **เปลี่ยนเส้นทาง** ไปยังหน้าล็อกอินโดยอัตโนมัติหากไม่มีเซสชันที่บันทึกไว้
- **สร้าง** ประสบการณ์การใช้งานที่ราบรื่นยิ่งขึ้นสำหรับผู้ใช้
**การทดสอบการใช้งานของคุณ:**
1. ล็อกอินเข้าสู่แอปธนาคารของคุณ
2. รีเฟรชหน้าเบราว์เซอร์
3. ตรวจสอบว่าคุณยังคงล็อกอินอยู่และอยู่ในหน้าแดชบอร์ด
4. ปิดและเปิดเบราว์เซอร์ใหม่
5. กลับไปยังแอปของคุณและยืนยันว่าคุณยังคงล็อกอินอยู่
🎉 **ความสำเร็จปลดล็อก**: คุณได้ทำการจัดการสถานะแบบถาวรสำเร็จแล้ว! แอปของคุณตอนนี้ทำงานเหมือนแอปพลิเคชันเว็บระดับมืออาชีพ
## การปรับสมดุลระหว่างการจัดการข้อมูลแบบถาวรกับความสดใหม่ของข้อมูล
ระบบการจัดการข้อมูลแบบถาวรของเราสามารถรักษาเซสชันของผู้ใช้ได้สำเร็จ แต่ก็สร้างความท้าทายใหม่: ข้อมูลที่ล้าสมัย เมื่อผู้ใช้หรือแอปพลิเคชันหลายตัวแก้ไขข้อมูลเซิร์ฟเวอร์เดียวกัน ข้อมูลที่แคชไว้ในเครื่องอาจไม่ทันสมัย
สถานการณ์นี้คล้ายกับนักเดินเรือไวกิ้งที่ใช้ทั้งแผนที่ดาวที่บันทึกไว้และการสังเกตการณ์ดาวปัจจุบัน แผนที่ให้ความสม่ำเสมอ แต่พวกเขาต้องการการสังเกตการณ์ใหม่เพื่อปรับตัวให้เข้ากับสภาพที่เปลี่ยนแปลง เช่นเดียวกัน แอปพลิเคชันของเราต้องการทั้งสถานะผู้ใช้ที่ถาวรและข้อมูลเซิร์ฟเวอร์ที่สดใหม่
**🧪 การค้นพบปัญหาความสดใหม่ของข้อมูล:**
1. ล็อกอินเข้าสู่แดชบอร์ดโดยใช้บัญชี `test`
2. รันคำสั่งนี้ในเทอร์มินัลเพื่อจำลองการทำธุรกรรมจากแหล่งอื่น:
```sh
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
```
3. รีเฟรชหน้าแดชบอร์ดในเบราว์เซอร์
4. สังเกตว่าคุณเห็นธุรกรรมใหม่หรือไม่
**สิ่งที่การทดสอบนี้แสดงให้เห็น:**
- **แสดง** ว่า localStorage อาจกลายเป็น "ล้าสมัย" (ไม่ทันสมัย)
- **จำลอง** สถานการณ์จริงที่ข้อมูลเปลี่ยนแปลงนอกแอปของคุณ
- **เผย** ความตึงเครียดระหว่างการจัดการข้อมูลแบบถาวรและความสดใหม่ของข้อมูล
**ความท้าทายของข้อมูลล้าสมัย:**
| ปัญหา | สาเหตุ | ผลกระทบต่อผู้ใช้ |
|-------|--------|-------------------|
| **ข้อมูลล้าสมัย** | localStorage ไม่หมดอายุโดยอัตโนมัติ | ผู้ใช้เห็นข้อมูลที่ไม่ทันสมัย |
| **การเปลี่ยนแปลงเซิร์ฟเวอร์** | แอป/ผู้ใช้อื่นแก้ไขข้อมูลเดียวกัน | มุมมองที่ไม่สอดคล้องกันระหว่างแพลตฟอร์ม |
| **แคช vs. ความเป็นจริง** | แคชในเครื่องไม่ตรงกับสถานะเซิร์ฟเวอร์ | ประสบการณ์ผู้ใช้ที่ไม่ดีและความสับสน |
**กลยุทธ์การแก้ปัญหา:**
เราจะใช้รูปแบบ "รีเฟรชเมื่อโหลด" ที่สมดุลระหว่างข้อดีของการจัดการข้อมูลแบบถาวรกับความต้องการข้อมูลที่สดใหม่ วิธีนี้จะช่วยรักษาประสบการณ์การใช้งานที่ราบรื่นในขณะที่รับรองความถูกต้องของข้อมูล
### งาน: การสร้างระบบรีเฟรชข้อมูล
เราจะสร้างระบบที่ดึงข้อมูลใหม่จากเซิร์ฟเวอร์โดยอัตโนมัติในขณะที่ยังคงรักษาข้อดีของการจัดการสถานะแบบถาวร
**ขั้นตอนที่ 1: สร้างฟังก์ชันอัปเดตข้อมูลบัญชี**
```js
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);
}
```
**การทำความเข้าใจตรรกะของฟังก์ชันนี้:**
- **ตรวจสอบ** ว่าผู้ใช้ล็อกอินอยู่หรือไม่ (state.account มีอยู่)
- **เปลี่ยนเส้นทาง** ไปยังหน้าล็อกเอาต์หากไม่มีเซสชันที่ถูกต้อง
- **ดึง** ข้อมูลบัญชีใหม่จากเซิร์ฟเวอร์โดยใช้ฟังก์ชัน `getAccount()` ที่มีอยู่
- **จัดการ** ข้อผิดพลาดของเซิร์ฟเวอร์อย่างราบรื่นโดยการล็อกเอาต์เซสชันที่ไม่ถูกต้อง
- **อัปเดต** สถานะด้วยข้อมูลใหม่โดยใช้ระบบอัปเดตที่ควบคุม
- **กระตุ้น** การจัดการข้อมูลแบบถาวรใน localStorage โดยอัตโนมัติผ่านฟังก์ชัน `updateState()`
**ขั้นตอนที่ 2: สร้างฟังก์ชันรีเฟรชแดชบอร์ด**
```js
async function refresh() {
await updateAccountData();
updateDashboard();
}
```
**สิ่งที่ฟังก์ชันรีเฟรชนี้ทำสำเร็จ:**
- **ประสานงาน** กระบวนการรีเฟรชข้อมูลและการอัปเดต UI
- **รอ** ให้ข้อมูลใหม่โหลดก่อนอัปเดตการแสดงผล
- **รับรอง** ว่าแดชบอร์ดแสดงข้อมูลที่ทันสมัยที่สุด
- **รักษา** การแยกที่ชัดเจนระหว่างการจัดการข้อมูลและการอัปเดต UI
**ขั้นตอนที่ 3: รวมเข้ากับระบบเส้นทาง**
อัปเดตการกำหนดค่าเส้นทางของคุณเพื่อกระตุ้นการรีเฟรชโดยอัตโนมัติ:
```js
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: refresh }
};
```
**วิธีการทำงานของการรวมนี้:**
- **ดำเนินการ** ฟังก์ชันรีเฟรชทุกครั้งที่โหลดเส้นทางแดชบอร์ด
- **รับรอง** ว่าข้อมูลใหม่จะแสดงเสมอเมื่อผู้ใช้ไปยังแดชบอร์ด
- **รักษา** โครงสร้างเส้นทางที่มีอยู่ในขณะที่เพิ่มความสดใหม่ของข้อมูล
- **ให้** รูปแบบที่สอดคล้องกันสำหรับการเริ่มต้นเฉพาะเส้นทาง
**การทดสอบระบบรีเฟรชข้อมูลของคุณ:**
1. ล็อกอินเข้าสู่แอปธนาคารของคุณ
2. รันคำสั่ง curl จากก่อนหน้านี้เพื่อสร้างธุรกรรมใหม่
3. รีเฟรชหน้าแดชบอร์ดหรือไปยังหน้าอื่นแล้วกลับมา
4. ตรวจสอบว่าธุรกรรมใหม่ปรากฏทันที
🎉 **สมดุลที่สมบูรณ์แบบ**: แอปของคุณตอนนี้รวมประสบการณ์การใช้งานที่ราบรื่นของสถานะถาวรเข้ากับความถูกต้องของข้อมูลเซิร์ฟเวอร์ที่สดใหม่!
## ความท้าทายของ GitHub Copilot Agent 🚀
ใช้โหมด Agent เพื่อทำความท้าทายต่อไปนี้:
**คำอธิบาย:** สร้างระบบการจัดการสถานะที่ครอบคลุมพร้อมฟังก์ชันย้อนกลับ/ทำซ้ำสำหรับแอปธนาคาร ความท้าทายนี้จะช่วยให้คุณฝึกฝนแนวคิดการจัดการสถานะขั้นสูง รวมถึงการติดตามประวัติสถานะ การอัปเดตแบบไม่เปลี่ยนแปลง และการซิงโครไนซ์กับส่วนติดต่อผู้ใช้
**คำสั่ง:** สร้างระบบการจัดการสถานะที่ปรับปรุงแล้วซึ่งรวมถึง: 1) อาร์เรย์ประวัติสถานะที่ติดตามสถานะก่อนหน้า, 2) ฟังก์ชันย้อนกลับและทำซ้ำที่สามารถย้อนกลับไปยังสถานะก่อนหน้า, 3) ปุ่ม UI สำหรับการย้อนกลับ/ทำซ้ำบนแดชบอร์ด, 4) ขีดจำกัดประวัติสูงสุด 10 สถานะเพื่อป้องกันปัญหาหน่วยความจำ, และ 5) การล้างประวัติอย่างเหมาะสมเมื่อผู้ใช้ออกจากระบบ รับรองว่าฟังก์ชันย้อนกลับ/ทำซ้ำทำงานร่วมกับการเปลี่ยนแปลงยอดคงเหลือบัญชีและยังคงอยู่หลังการรีเฟรชเบราว์เซอร์
เรียนรู้เพิ่มเติมเกี่ยวกับ [โหมด Agent](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) ที่นี่
## 🚀 ความท้าทาย: การปรับปรุงการจัดเก็บข้อมูล
การใช้งานของคุณตอนนี้จัดการเซสชันผู้ใช้ การรีเฟรชข้อมูล และการจัดการสถานะได้อย่างมีประสิทธิภาพ อย่างไรก็ตาม ลองพิจารณาว่าวิธีการปัจจุบันของเราสมดุลระหว่างประสิทธิภาพการจัดเก็บข้อมูลกับฟังก์ชันการทำงานได้ดีที่สุดหรือไม่
เหมือนกับนักหมากรุกที่แยกแยะระหว่างตัวหมากที่สำคัญและตัวหมากที่สามารถเสียได้ การจัดการสถานะที่มีประสิทธิภาพต้องระบุว่าข้อมูลใดที่ต้องจัดเก็บถาวรและข้อมูลใดที่ควรดึงจากเซิร์ฟเวอร์เสมอ
**การวิเคราะห์การปรับปรุง:**
ประเมินการใช้งาน localStorage ปัจจุบันของคุณและพิจารณาคำถามเชิงกลยุทธ์เหล่านี้:
- ข้อมูลขั้นต่ำที่จำเป็นในการรักษาการตรวจสอบสิทธิ์ของผู้ใช้คืออะไร?
- ข้อมูลใดที่เปลี่ยนแปลงบ่อยจนการแคชในเครื่องไม่มีประโยชน์?
- การปรับปรุงการจัดเก็บข้อมูลสามารถเพิ่มประสิทธิภาพได้โดยไม่ลดทอนประสบการณ์ผู้ใช้ได้อย่างไร?
**กลยุทธ์การใช้งาน:**
- **ระบุ** ข้อมูลสำคัญที่ต้องจัดเก็บถาวร (อาจเป็นเพียงข้อมูลการระบุตัวตนของผู้ใช้)
- **ปรับเปลี่ยน** การใช้งาน localStorage ของคุณเพื่อจัดเก็บเฉพาะข้อมูลเซสชันที่สำคัญ
- **รับรอง** ว่าข้อมูลใหม่จะถูกโหลดจากเซิร์ฟเวอร์เสมอเมื่อเยี่ยมชมแดชบอร์ด
- **ทดสอบ** ว่าวิธีการที่ปรับปรุงแล้วของคุณยังคงรักษาประสบการณ์ผู้ใช้เดิม
**การพิจารณาขั้นสูง:**
- **เปรียบเทียบ** ข้อดีข้อเสียระหว่างการจัดเก็บข้อมูลบัญชีทั้งหมดกับการจัดเก็บเฉพาะโทเค็นการตรวจสอบสิทธิ์
- **บันทึก** การตัดสินใจและเหตุผลของคุณสำหรับสมาชิกทีมในอนาคต
ความท้าทายนี้จะช่วยให้คุณคิดเหมือนนักพัฒนามืออาชีพที่พิจารณาทั้งประสบการณ์ผู้ใช้และประสิทธิภาพของแอปพลิเคชัน ใช้เวลาในการทดลองกับวิธีการต่าง ๆ!
## แบบทดสอบหลังการบรรยาย
[แบบทดสอบหลังการบรรยาย](https://ff-quizzes.netlify.app/web/quiz/48)
## งานที่ได้รับมอบหมาย
[สร้างหน้าต่าง "เพิ่มธุรกรรม"](assignment.md)
นี่คือตัวอย่างผลลัพธ์หลังจากทำงานที่ได้รับมอบหมายเสร็จ:
![ภาพหน้าจอแสดงตัวอย่างหน้าต่าง "เพิ่มธุรกรรม"](../../../../translated_images/dialog.93bba104afeb79f12f65ebf8f521c5d64e179c40b791c49c242cf15f7e7fab15.th.png)
---
**ข้อจำกัดความรับผิดชอบ**:
เอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้การแปลมีความถูกต้อง แต่โปรดทราบว่าการแปลอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่ถูกต้อง เอกสารต้นฉบับในภาษาดั้งเดิมควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลสำคัญ ขอแนะนำให้ใช้บริการแปลภาษามืออาชีพ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความผิดที่เกิดจากการใช้การแปลนี้