バッチ更新
複数の Signal 更新をバッチ処理して、Effect を一度だけトリガーします。
問題
バッチなしでは、各 Signal 更新が Effect を即座にトリガーします:
const [firstName, setFirstName] = createSignal("John");
const [lastName, setLastName] = createSignal("Doe");
createEffect(() => {
console.log(`Name: ${firstName()} ${lastName()}`);
});
// 2つの別々の更新 = 2回の Effect 実行
setFirstName("Jane"); // Effect 実行: "Jane Doe"
setLastName("Smith"); // Effect 実行: "Jane Smith"
これにより以下が発生する可能性があります:
不要な再レンダリング
一貫性のない中間状態
パフォーマンスの問題
Batch の使用
import { createSignal, createEffect, batch } from '@luna_ui/luna';
const [firstName, setFirstName] = createSignal("John");
const [lastName, setLastName] = createSignal("Doe");
createEffect(() => {
console.log(`Name: ${firstName()} ${lastName()}`);
});
// バッチ = 1回の Effect 実行
batch(() => {
setFirstName("Jane");
setLastName("Smith");
});
// Effect は一度だけ実行: "Jane Smith"
Batch を使うタイミング
関連する複数の更新
const [user, setUser] = createSignal(null);
const [loading, setLoading] = createSignal(true);
const [error, setError] = createSignal(null);
async function fetchUser() {
setLoading(true);
try {
const data = await api.getUser();
// すべてを一度に更新
batch(() => {
setUser(data);
setLoading(false);
setError(null);
});
} catch (e) {
batch(() => {
setUser(null);
setLoading(false);
setError(e.message);
});
}
}
フォーム更新
function resetForm() {
batch(() => {
setName("");
setEmail("");
setPhone("");
});
}
Batch は同期的
Batch は同期的に実行され、すべての更新後に戻ります:
const [count, setCount] = createSignal(0);
batch(() => {
setCount(1);
setCount(2);
setCount(3);
});
console.log(count()); // 3(batch 直後)
ネストした Batch
ネストした batch はフラット化されます - Effect は最も外側の batch 後に実行:
const [a, setA] = createSignal(0);
const [b, setB] = createSignal(0);
createEffect(() => console.log(a(), b()));
batch(() => {
setA(1);
batch(() => {
setB(2); // まだ外側の batch 内
});
setA(3);
});
// Effect は一度だけ実行: 3, 2
よくある間違い
Batch 内の非同期
Batch は同期コードにのみ影響します:
// 間違い: async が batch を壊す
batch(async () => {
setLoading(true);
const data = await fetch(...); // batch はここで終了!
setData(data); // バッチされない
setLoading(false); // バッチされない
});
// 正しい: 非同期後に batch
async function load() {
setLoading(true);
const data = await fetch(...);
batch(() => {
setData(data);
setLoading(false);
});
}
試してみよう
RGB スライダーを持つカラーミキサーを作成し、すべてのスライダーが変更されたときにプレビューを一度だけ更新:
解答
const [r, setR] = createSignal(128);
const [g, setG] = createSignal(128);
const [b, setB] = createSignal(128);
const color = createMemo(() => `rgb(${r()}, ${g()}, ${b()})`);
createEffect(() => {
console.log("Color updated:", color());
});
function setPreset(preset) {
batch(() => {
setR(preset.r);
setG(preset.g);
setB(preset.b);
});
}
// 使用
setPreset({ r: 255, g: 0, b: 0 }); // 1回の Effect 実行
次へ
Untrack → について学ぶ