Dev to webs {Coding…}

เรียนรู้การพัฒนาซอฟเวอร์ เพื่อความรู้ที่ยั่งยืน

บทที่ 33: การสร้าง Store แบบ Dynamic


1. ความเข้าใจเกี่ยวกับ Store แบบ Dynamic

Store แบบ Dynamic ใน Alpine.js ช่วยให้คุณสามารถสร้าง State หรือข้อมูลที่ปรับเปลี่ยนได้ในเวลาทำงาน โดยใช้ฟังก์ชันภายใน Store

  • ใช้สำหรับสถานการณ์ที่ต้องการสร้างข้อมูลใหม่หลายชุด เช่น สร้างผู้ใช้ใหม่, เพิ่มรายการในฟอร์ม, หรือ ตั้งค่าที่เปลี่ยนแปลงได้
  • ฟังก์ชันใน Store จะทำหน้าที่สร้างและจัดการ State เหล่านี้

2. โครงสร้างการสร้าง Store แบบ Dynamic

<script>
    document.addEventListener('alpine:init', () => {
        Alpine.store('dynamicStore', {
            items: [],
            addItem(newItem) {
                this.items.push(newItem);
            },
            resetItems() {
                this.items = [];
            }
        });
    });
</script>

คำอธิบาย:

  • Store ชื่อ dynamicStore เก็บข้อมูลในรูปแบบ Array (items) พร้อมฟังก์ชัน addItem(newItem) และ resetItems() สำหรับจัดการข้อมูล

3. การสร้าง Store เพื่อจัดการ State แบบ Dynamic

ตัวอย่าง 1: เพิ่มรายการใน Store
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.store('tasks', {
            tasks: [],
            addTask(task) {
                this.tasks.push({ id: Date.now(), name: task });
            }
        });
    });
</script>

<div x-data>
    <input x-ref="taskInput" type="text" placeholder="Enter a task">
    <button @click="$store.tasks.addTask($refs.taskInput.value)">Add Task</button>
    <ul>
        <template x-for="task in $store.tasks.tasks" :key="task.id">
            <li x-text="task.name"></li>
        </template>
    </ul>
</div>

คำอธิบาย:

  • Store tasks มีฟังก์ชัน addTask(task) ที่สร้าง Task ใหม่พร้อม ID ที่ไม่ซ้ำ
  • ปุ่ม Add Task เรียกใช้ฟังก์ชันเพื่อเพิ่ม Task ใหม่

4. การสร้าง State แบบ Dynamic ใน Object ซ้อนลึก

ตัวอย่าง 2: จัดการข้อมูลผู้ใช้หลายคน
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.store('userStore', {
            users: [],
            addUser(name, age) {
                this.users.push({ id: Date.now(), name, age });
            },
            removeUser(id) {
                this.users = this.users.filter(user => user.id !== id);
            }
        });
    });
</script>

<div x-data>
    <input x-ref="nameInput" type="text" placeholder="Name">
    <input x-ref="ageInput" type="number" placeholder="Age">
    <button @click="$store.userStore.addUser($refs.nameInput.value, $refs.ageInput.value)">Add User</button>
    <ul>
        <template x-for="user in $store.userStore.users" :key="user.id">
            <li>
                <span x-text="`Name: ${user.name}, Age: ${user.age}`"></span>
                <button @click="$store.userStore.removeUser(user.id)">Remove</button>
            </li>
        </template>
    </ul>
</div>

คำอธิบาย:

  • ฟังก์ชัน addUser(name, age) เพิ่มผู้ใช้ใหม่ใน Store userStore
  • ฟังก์ชัน removeUser(id) ลบผู้ใช้ตาม ID

5. การสร้าง Store เพื่อจัดการข้อมูลฟอร์มแบบ Dynamic

ตัวอย่าง 3: เพิ่มฟิลด์ Input แบบ Dynamic
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.store('formStore', {
            fields: [],
            addField(label) {
                this.fields.push({ id: Date.now(), label, value: '' });
            },
            removeField(id) {
                this.fields = this.fields.filter(field => field.id !== id);
            }
        });
    });
</script>

<div x-data>
    <input x-ref="fieldLabel" type="text" placeholder="Field Label">
    <button @click="$store.formStore.addField($refs.fieldLabel.value)">Add Field</button>
    <div>
        <template x-for="field in $store.formStore.fields" :key="field.id">
            <div>
                <label x-text="field.label"></label>
                <input type="text" x-model="field.value">
                <button @click="$store.formStore.removeField(field.id)">Remove</button>
            </div>
        </template>
    </div>
</div>

คำอธิบาย:

  • ฟังก์ชัน addField(label) เพิ่มฟิลด์ใหม่พร้อม Label และค่า value เริ่มต้น
  • ฟังก์ชัน removeField(id) ลบฟิลด์ตาม ID

6. การใช้ Dynamic State กับ Transition

ตัวอย่าง 4: เพิ่ม/ลบรายการพร้อม Transition
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.store('listStore', {
            items: [],
            addItem(content) {
                this.items.push({ id: Date.now(), content });
            },
            removeItem(id) {
                this.items = this.items.filter(item => item.id !== id);
            }
        });
    });
</script>

<div x-data>
    <input x-ref="itemInput" type="text" placeholder="Add item">
    <button @click="$store.listStore.addItem($refs.itemInput.value)">Add Item</button>
    <ul>
        <template x-for="item in $store.listStore.items" :key="item.id">
            <li x-text="item.content" x-transition>
                <button @click="$store.listStore.removeItem(item.id)">Remove</button>
            </li>
        </template>
    </ul>
</div>

คำอธิบาย:

  • เพิ่ม Transition ให้กับรายการเมื่อถูกเพิ่มหรือถูกลบ
  • ฟังก์ชัน addItem(content) และ removeItem(id) จัดการข้อมูลแบบ Dynamic

7. ข้อควรระวังในการสร้าง Store แบบ Dynamic

  1. การจัดการข้อมูลซ้อนลึก:
    • ควรใช้โครงสร้างข้อมูลที่เหมาะสมและจัดการค่าซ้อนลึกอย่างรอบคอบ
  2. การอ้างอิง State ในหลาย Component:
    • หาก Component หลายตัวใช้ Store เดียวกัน ควรตรวจสอบการเปลี่ยนแปลง State อย่างเหมาะสม
  3. การกำหนด Key:
    • ใช้ Key ที่ไม่ซ้ำ (เช่น Date.now() หรือ UUID) เพื่อป้องกันปัญหาใน Transition และการแสดงผล

สรุป

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับ การสร้าง Store แบบ Dynamic ใน Alpine.js เพื่อจัดการ State ที่สามารถปรับเปลี่ยนได้ในเวลาทำงาน ตัวอย่างครอบคลุมการเพิ่ม/ลบข้อมูลใน Array, การจัดการข้อมูลฟอร์ม, และการใช้ Transition เพื่อทำให้ UI ดูน่าสนใจขึ้น การสร้าง Store แบบ Dynamic ช่วยให้ Component มีความยืดหยุ่นและตอบสนองต่อความต้องการของผู้ใช้ได้ดีขึ้น!