如何在Svelte Store更新前校验修改值?避免二次更新
解决Svelte Store更新前校验导致两次更新的问题
当使用数字输入框绑定Svelte Store属性时,输入非法值(如-1)会导致Store先更新为错误值,再被反应式语句修正为正确值,触发两次Store更新。以下是几种解决方法:
方案一:使用本地变量+手动校验更新
通过本地变量绑定输入框,在变量变化时先完成校验修正,再更新Store,确保Store只接收正确值:
<script> import { availableTrainingMaterials } from '$stores'; let t1Value = $availableTrainingMaterials.T1; $: { // 确保值不小于0 const correctedValue = Math.max(t1Value, 0); // 只有值变化时才更新Store if (correctedValue !== $availableTrainingMaterials.T1) { availableTrainingMaterials.update(store => { store.T1 = correctedValue; return store; }); } // 同步输入框显示修正后的值 t1Value = correctedValue; } </script> <div class="available-materials"> <h2>我拥有的材料:</h2> <div> T1: <input bind:value={t1Value} type="number" /> </div> </div>
方案二:自定义带校验逻辑的Store
把校验逻辑封装到Store内部,任何更新操作都会自动经过校验,从根源避免错误值进入Store:
修改Store.js:
import { writable } from 'svelte/store'; function createMaterialsStore() { const { subscribe, set, update } = writable({ T1: 0 }); return { subscribe, // 自定义更新T1的方法,内置校验 updateT1: (newValue) => { const correctedValue = Math.max(newValue, 0); update(store => { store.T1 = correctedValue; return store; }); }, // 带校验的整体设置方法 set: (newStore) => { const correctedStore = { ...newStore, T1: Math.max(newStore.T1, 0) }; set(correctedStore); } }; } export const availableTrainingMaterials = createMaterialsStore();
修改Materials.svelte:
<script> import { availableTrainingMaterials } from '$stores'; let t1Value = $availableTrainingMaterials.T1; // 输入变化时调用自定义更新方法 $: availableTrainingMaterials.updateT1(t1Value); </script> <div class="available-materials"> <h2>我拥有的材料:</h2> <div> T1: <input bind:value={t1Value} type="number" /> </div> </div>
方案三:通过输入事件直接处理
监听输入框的input事件,在事件回调中完成值的校验修正,再更新Store:
<script> import { availableTrainingMaterials } from '$stores'; function handleInput(e) { let value = Number(e.target.value); // 校验修正值 value = Math.max(value, 0); // 更新Store availableTrainingMaterials.update(store => { store.T1 = value; return store; }); // 同步输入框显示正确值 e.target.value = value; } </script> <div class="available-materials"> <h2>我拥有的材料:</h2> <div> T1: <input value={$availableTrainingMaterials.T1} type="number" on:input={handleInput} /> </div> </div>
内容的提问来源于stack exchange,提问作者mhaklander
相关产品推荐
相关产品推荐

