Pawel Kozlowski有一条非常被低估的推文:
在本文中,让我们将该MOBX文章中的示例应用于角信号。
在示例中,我将在包含$符号的信号的前缀变量:$itIsSignal
。没有此前缀的变量和字段不是信号。阅读本文后,您可能会同意,它有助于查看应将其称为要读(并观察)的函数。或者您可能决定不使用此公约 - 我不坚持您:)
示例是从MOBX文章示例中转换的,但我将用阅读和跟踪功能取代词语'观看函数(或只是watcher()
),因为在角度信号中,需要在观察功能中读取信号才能观察到。
现在,Angular已实现了两个观察者:effect()
功能和模板。他们在角信号反应性中实现了相同的角色,因此我将使用watcher()
引用两个。
让我们已经开始:
import { signal } from "@angular/core";
type Author = {
$name: WritableSignal<string>;
$age?: WritableSignal<number | undefined>;
};
class Message {
$title: WritableSignal<string>;
$author: WritableSignal<Author>;
$likes: WritableSignal<string[]>;
constructor(title: string, author: string, likes: string[]) {
this.$title = signal(title);
this.$author = signal({
$name: signal(author)
});
this.$likes = signal(likes);
}
updateTitle(title: string) {
this.$title.set(title);
}
}
let message = new Message('Foo', 'Michel', ['Joe', 'Sara']);
正确:阅读观看功能
watcher(() => {
console.log(message.$title());
});
message.updateTitle('Bar');
在这里,我们将在控制台中收到预期的更新,因为watcher()
已读取$title
,此后,它将在接收到更新通知时重新阅读此信号。
不正确:更改不可观察的参考
watcher(() => {
console.log(message.$title());
});
message = new Message('Bar', 'Martijn', ['Felicia', 'Marcus']);
在这里,我们替换了消息,但是watcher()
使用了对另一个变量的引用,并且不会通知我们替换了参考。
不正确:在观看功能之外读取信号
const title = message.$title();
watcher(() => {
console.log(title);
});
message.updateTitle('Bar');
在这里,title
不是信号。这是我们在观看功能之外阅读的值,因此在我们更新信号时不会通知watcher()
。
正确:阅读观看功能
watcher(() => {
console.log(message.$author().$name());
});
message.$author().$name.set("Sara");
message.$author.set({
$name: signal("Joe")
});
在watcher()
函数中,我们读取$author
和$name
。因此,每次我们更新它们中的任何一个时,都会通知watcher()
。
不正确:在不阅读的情况下存储对观察信号的本地引用
const author = message.$author();
watcher(() => {
console.log(author.$name());
});
message.$author().$name.set("Sara");
message.$author = signal({ $name: signal("Joe") });
第一个更改将被捡起,message.$author()
和author
是同一对象,并且在watcher()
中读取.$name
属性。
但是,第二个更改没有得到拾取,因为watcher()
并未跟踪watcher()
的关系。 watcher()
仍在使用旧author
。
ð普通陷阱:console.log
watcher(() => {
console.log(message);
});
// Won't trigger a re-run.
message.updateTitle("Hello world");
在上面的示例中,更新的消息标题会被打印,因为它没有在watcher()
中读取。 watcher()
仅取决于消息变量,这不是信号,而是常规变量。换句话说,$title
没有由watcher()
读取。
正确:更新对象
watcher(() => {
console.log(message.$likes().length);
});
message.$likes.mutate(likes => likes.push("Jennifer"));
message.$likes.update(likes => ([...likes, "Jennifer"]));
这将按预期工作:在角信号中,调用mutate()
方法将始终导致更新通知。
如果一个角信号包含一个对象,则默认情况下,新值将始终被视为与上一个值不相等(除非您覆盖相等性检查功能)。结果,第二行还将触发更新通知。
不正确:读取信号异步
watcher(() => {
setTimeout(() => {
console.log(message.$likes().join(", "));
}, 10);
});
message.$likes.mutate(likes => likes.push("Jennifer"));
在角信号中,观察功能无法检测异步呼叫中的反应性图依赖性。
结论
利用其他框架和从我们自己的实验中的知识积累的经验,我们可以在无反应性列车中完全释放自动依赖性跟踪的力量。