本章节详细介绍了 Oref 提供的实用工具函数。这些函数旨在简化开发过程,提高代码效率,并增强类型安全性。无论您是在处理响应式引用、进行类型检查,还是优化 Flutter 小部件,这里的工具函数都能为您的开发工作提供有力支持。
isRef()
检查一个值是否是 Ref<T>
。
类型
dartbool isRef(Object? value);
isRef()
没有声明特别的,它只是 is
的函数式封装。如果你不喜欢函数风格,你完全可以使用 value is Ref
替代。
isReactive()
0.4+
检查一个对象是否是一个响应式集合。
- 类型dart
bool isReactive<T>(T value);
unref()
如果参数是一个 Ref<T>
那么返回其内部的响应式值,否则返回本身。
这是 return isRef(value) ? value.value : value
的三元计算语法糖。
- 类型dart
R unref<R>(R value); R unref<R>(Ref<R> ref);
- 示例
useCounter(/* int | Ref<int> */ count) { final int unwrapped = unref(count); // unwrapped 现在保证为 number 类型 }
- 注意事项 适用于你确定变量是
T | Ref<T>
类型实用,如果你无法确定类型,请使用 dynamic 进行接收:dartfinal unwrapped = unref(value);
toWidgetRef()
Flutter
将一个 Widget 对象转换为 Ref<T extends Widget>
对象的引用。
import 'package:oref_flutter/oref_flutter.dart';
class MyWidget extends StatelessWidget {
const MyWidget({super.key, required this.name});
final String name;
Widget build(BuildContext context) {
final widgetRef = toWidgetRef(context, this);
effect(() => print(widgetRef.value.name);
return ...;
}
}
当你的 Widget 与 Oref 进行搭配使用时,如果你使用 this.name
仅在第一次 build 时生效。 当你在祖先更新 MyWidget
的 name
参数时,由于 name
并非响应式的,因此 rebuild
不会在 Oref 的作用域中生效。我们看这个简单的例子:
class Counter extends StatelessWidget {
const Counter({super.key, required this.correct});
final int correct;
Widget build(BuildContext context) {
final count = ref(context, 0);
final computed = derived(() => count.value + correct);
return TextButton(
onPressed: () => count.value++,
child: Text('${computed.value}'),
);
}
}
在上层无论我们如何更新 correct
的值,都不会生效。原因普通对象不具备响应性,因此我们需要将 correct
转换为响应式的值。 但如果我们为每一个属性都进行响应式包装未免也太过于麻烦,毕竟实际场景下可能会有许多属性值。 所以将整个 Widget 对象转换为 Ref 是最为稳妥的方式:
class Counter extends StatelessWidget {
const Counter({super.key, required this.correct});
final int correct;
Widget build(BuildContext context) {
final widgetRef = toWidgetRef(context, this);
final count = ref(context, 0);
final computed = derived(() => count.value + widgetRef.value.correct);
return TextButton(
onPressed: () => count.value++,
child: Text('${computed.value}'),
);
}
}
推测返回类型(inferReturnType()
) v0.5+
inferReturnType()
函数用于推断并正确包装传入函数的返回类型:
// 推断的返回类型: ({String name, DateTime createdAt})
final say = inferReturnType((String name) => (name: name, createdAt: DateTime.now()));
为什么需要它?
在使用 Oref 的响应式 API 构建新的可组合 API 时,Dart 通常要求我们显式定义函数的返回类型:
({T Function() valueOf, void Function() increment}) useCounter<T>() {
final count = ref(0);
void increment() => count.value++;
return (
valueOf: () => count.value as T,
increment: increment
);
}
这种做法会导致大量样板代码,降低了代码的可读性和维护性。
规避 lint 规则警告
虽然使用变量定义函数可以达到类似的效果:
final useCounter = () {
final count = ref(0);
void increment() => count.value++;
return (
valueOf: () => count.value,
increment: increment
);
};
但这种写法会触发 lint 规则警告(prefer_function_declarations_over_variables
)。为了规避这个问题并避免编写冗长的类型声明,我们可以使用 inferReturnType()
函数。
实现原理
inferReturnType()
的实现非常简单,仅需一行代码:
F inferReturnType<F extends Function>(F fn) => fn;
这个函数利用 Dart 的类型推断机制,帮助开发者在不显式声明复杂返回类型的情况下,保持代码的简洁性和类型安全性。