Event Handling & Updating Block Attributes
Gambaran Umum
Video ini membahas cara menghubungkan UI dengan block attributes — menyimpan nilai question, mengelola array answers (tambah/edit/hapus), dan memahami pola React untuk immutable state updates.
1. Update Question Attribute
Mendefinisikan Attribute
attributes: {
question: { type: 'string' },
answers: { type: 'array', default: [''] },
correctAnswer: { type: 'number', default: undefined }
},Hook Up Question Field
function EditComponent(props) {
function updateQuestion(value) {
// TextControl langsung memberikan value (bukan event)
props.setAttributes({ question: value });
}
return (
<div className="paying-attention-edit-block">
<TextControl
label="Question:"
value={props.attributes.question}
onChange={updateQuestion}
style={{ fontSize: "20px" }}
/>
{/* ... answers section */}
</div>
);
}Penting: WordPress
TextControlcomponent mempassing value langsung keonChangehandler, bukaneventobject. Ini berbeda dari HTML<input>biasa yang mempassingevent.target.value.
2. Looping Answers dengan map()
Konsep
Setiap item di array answers menjadi satu baris input field. Gunakan JavaScript Array.map() untuk loop:
{props.attributes.answers.map(function(answer, index) {
return (
<Flex>
<FlexBlock>
<TextControl
value={answer}
onChange={(newValue) => {
// Update satu item spesifik di array
const newAnswers = props.attributes.answers.concat([]);
newAnswers[index] = newValue;
props.setAttributes({ answers: newAnswers });
}}
/>
</FlexBlock>
<FlexItem>
<Button onClick={() => markAsCorrect(index)}>
<Icon icon="star-empty" className="mark-as-correct" />
</Button>
</FlexItem>
<FlexItem>
<Button isLink className="attention-delete" onClick={() => deleteAnswer(index)}>
Delete
</Button>
</FlexItem>
</Flex>
);
})}Mengapa Tidak Langsung Mutate Array?
Di React, jangan pernah langsung mengubah state:
// ❌ SALAH — mutasi langsung:
props.attributes.answers[index] = newValue;
// ✅ BENAR — buat salinan, ubah salinan:
const newAnswers = props.attributes.answers.concat([]); // Copy array
newAnswers[index] = newValue; // Ubah copy
props.setAttributes({ answers: newAnswers }); // Set via WordPress
.concat([])— Trik untuk membuat shallow copy array baru. Array baru ini boleh dimutasi karena bukan state asli.
3. Tambah Answer Baru
<Button isPrimary onClick={() => {
props.setAttributes({
answers: props.attributes.answers.concat(['']) // Tambah empty string ke akhir
});
}}>
Add another answer
</Button>
.concat([''])mengembalikan array baru dengan item tambahan — tidak memutasi array asli. Jangan gunakan.push()karena itu mutasi langsung.
4. Hapus Answer
function deleteAnswer(indexToDelete) {
const newAnswers = props.attributes.answers.filter(function(x, index) {
return index != indexToDelete;
});
props.setAttributes({ answers: newAnswers });
}Penjelasan filter():
filter()mengembalikan array baru yang hanya berisi item yang lolos kondisi- Untuk setiap item: jika
index != indexToDelete→ include (return true) - Item yang index-nya sama dengan yang ingin dihapus → exclude (return false)
5. Focus Otomatis pada Field Baru
Tip dari Brad: Saat user klik "Add another answer", field baru bisa otomatis ter-focus:
Langkah 1: Gunakan undefined alih-alih empty string
<Button isPrimary onClick={() => {
props.setAttributes({
answers: props.attributes.answers.concat([undefined]) // ← undefined, bukan ''
});
}}>
Add another answer
</Button>Langkah 2: Tambahkan autoFocus prop
<TextControl
autoFocus={answer === undefined} // Auto-focus hanya field yang baru ditambahkan
value={answer}
onChange={...}
/>Field yang baru ditambah memiliki value
undefined(satu-satunya yangundefined), sehinggaautoFocushanya aktif untuk field baru tersebut.
Ringkasan Pola React di WordPress Blocks
| Operasi | Pendekatan |
|---|---|
| Update satu item di array | Copy array dengan .concat([]), ubah copy, setAttributes() |
| Tambah item ke array | .concat(['']) untuk menambah tanpa mutasi |
| Hapus item dari array | .filter() untuk membuat array baru tanpa item tertentu |
| Jangan pernah | Langsung mutasi props.attributes |
Alur Data:
User types in field
→ onChange fires
→ Create copy of answers array
→ Modify the copy
→ props.setAttributes({ answers: newCopy })
→ React re-renders component
→ UI ter-update