TinyBase 指南:使用监听器实现数据变更校验
监听器的默认行为
在 TinyBase 中,监听器(listeners)默认是不能修改数据的。这是一个重要的安全机制,防止在监听数据变化时产生意外的副作用或无限循环。
让我们看一个典型场景:假设我们希望在颜色值被设置为"walnut"时自动将其更正为"brown"。初学者可能会尝试以下代码:
import {createStore} from 'tinybase';
const store = createStore();
store.setRow('pets', 'fido', {species: 'dog', color: 'black'});
const colorListenerId = store.addCellListener(
'pets',
null,
'color',
(store, tableId, rowId, cellId, newCell) => {
if (newCell == 'walnut') {
store.setCell(tableId, rowId, cellId, 'brown');
}
},
);
store.setCell('pets', 'fido', 'color', 'walnut');
console.log(store.getTables());
// 输出结果:{pets: {fido: {species: 'dog', color: 'walnut'}}}
可以看到,虽然我们在监听器中尝试修改数据,但实际上修改并未生效,数据仍然保持为"walnut"。
启用监听器修改权限
TinyBase 提供了显式的机制来允许监听器修改数据,这通过设置 mutator
标志为 true
来实现。这种设计既保证了安全性,又提供了灵活性。
让我们看一个更实用的例子:确保宠物种类只能是预定义的几种类型之一:
const SPECIES = ['unknown', 'dog', 'cat', 'worm'];
store.addCellListener(
'pets',
null,
'species',
(store, tableId, rowId, cellId, newCell) => {
if (!SPECIES.includes(newCell)) {
store.setCell(tableId, rowId, cellId, SPECIES[0]);
}
},
true, // 关键:允许此监听器修改Store
);
store.setCell('pets', 'fido', 'species', 'worm'); // 有效值
console.log(store.getTables());
// 输出:{pets: {fido: {species: 'worm', color: 'walnut'}}}
store.setCell('pets', 'fido', 'species', 'wolf'); // 无效值
console.log(store.getTables());
// 输出:{pets: {fido: {species: 'unknown', color: 'walnut'}}}
监听器执行顺序
TinyBase 对监听器的执行顺序有明确的规则:
- 所有标记为 mutator 的监听器会优先执行
- 然后才是普通的只读监听器
这种执行顺序确保了当你的只读监听器被触发时,Store 中的数据已经被所有 mutator 监听器处理完毕,处于最终状态。
实际应用场景
这种机制在实际开发中有多种应用:
- 数据校验:确保数据符合特定格式或范围
- 数据标准化:自动转换输入数据为统一格式
- 数据补全:自动填充缺失的字段或默认值
- 数据关联:保持相关字段的一致性(需注意避免循环依赖)
例如,你可以实现:
- 数值范围限制(如年龄必须在0-150之间)
- 字符串格式转换(如自动转为小写)
- 枚举值校验(如状态只能是"pending"/"completed"/"cancelled")
- 关联字段同步(如修改城市时自动更新国家)
注意事项
使用 mutator 监听器时需要注意:
- 性能考虑:复杂的校验逻辑可能影响性能
- 循环风险:避免监听器之间相互触发导致无限循环
- 明确性:应该清晰地标记哪些监听器会修改数据
- 可预测性:确保修改行为对所有使用者都是可预测的
总结
通过 TinyBase 的 mutator 监听器机制,我们可以在数据变更时实现灵活的业务逻辑校验和自动修正。这种模式实际上实现了一种"程序化模式(programmatic schema)",相比静态模式定义更加灵活,能够处理更复杂的业务规则。
这种技术特别适合在数据加载阶段进行清洗和标准化,确保应用始终处理符合预期的数据。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考