想象一下 Angular 中的标准情况:您需要从服务器获取某些实体 ID 的数据。实体 ID 是一个信号,您希望获取的数据也成为信号。
像这样的事情感觉很自然:
@Component({
selector: 'my-app',
standalone: true,
imports: [CommonModule],
template: `
<code>{{roles()}}</code>
`,
})
export class App {
userId: Signal<string> = signal('userA');
roles = computed(() => toSignal(getRoles(this.userId())));
}
//this could be api service sending http request
const getRoles = (userId: string) => {
return userId === 'userA' ? of([1, 2, 3]) : of([1]);
};
Run Code Online (Sandbox Code Playgroud)
但浏览器控制台出现运行时错误:
Error: NG0203: toSignal() can only be used within an injection context such as a constructor, a factory function, a …Run Code Online (Sandbox Code Playgroud) 我正在尝试在 Angular 应用程序中切换到信号,目前在寻找良好实践方面遇到问题,并且我也经历了(至少对我来说)意外的行为。
这是我的代码片段,由一个 userService 和两个组件组成
export class UserService {
private user$: Observable<User>;
private refreshUser$ = new BehaviorSubject<void>(undefined);
constructor(private readonly http: HttpClient) {}
getUser(): Observable<User> {
if (!this.user$) {
this.user$ = this.refreshUser$.pipe(
switchMap(() => this.http.get<User>('...')),
shareReplay(1)
);
}
return this.user$;
}
reloadUser(): void {
this.refreshUser$.next();
}
}
Run Code Online (Sandbox Code Playgroud)
然后我有组件 A 为用户订阅:
export class aComponent {
currentUser: User;
constructor(private readonly userService: UserService) {
this.userService.getUser().subscribe((user) => {
this.currentUser = user;
});
}
}
Run Code Online (Sandbox Code Playgroud)
我有组件 aChild,它是组件 A 的子组件,也订阅用户并且还可以操作用户。它能够更改/删除用户的地址。在使用信号之前,我会立即更新组件的 currentUser 对象的地址,以便用户可以立即看到结果,并且我会从服务调用“reloadUser()”,以便全局用户是最新的,并且“A Component " 具有正确的值(这可能不是最好的解决方案,因为它会导致另一个 http …
rxjs angular2-changedetection angular angular-signals angular16
我试图了解使用 Angular Signals 的优势。许多解释中都给出了一个计数示例,但我试图理解的是,以这种方式使用信号的优点与我在下面通过变量 myCount 和 myCountDouble 所做的方式相反?
\nhttps://stackblitz.com/edit/angular-qtd3ku?file=src/main.ts
\n这是我的代码+ stackblitz
\nimport \'zone.js/dist/zone\';\nimport { Component } from \'@angular/core\';\nimport { bootstrapApplication } from \'@angular/platform-browser\';\nimport { signal } from \'./signals/signal\';\nimport { computed } from \'./signals/computed\';\nimport { effect } from \'./signals/effect\';\nimport { TestArraysCmp } from \'./testing-arrays.component\';\nimport { TestObjectsCmp } from \'./testing-objects.component\';\n\n/*\n \xe2\x9a\xa0\xef\xb8\x8f Please keep in mind that this is only the signals implementation. We still depend on zone and current CD strategy to propagate change in the template which might …Run Code Online (Sandbox Code Playgroud) 我将 Angular 应用程序更新到 v16,并尝试使用 Signals。之前,我在没有初始值的情况下初始化变量
filters: Filter[];
Run Code Online (Sandbox Code Playgroud)
但当我使用信号时,它给了我一个错误。
An argument for 'initialValue' was not provided
有没有办法可以在不初始化信号值的情况下创建信号?
我尝试将其 Type 设置为可能为 null 并赋予它 null 值
signal<Category | null>(null);
Run Code Online (Sandbox Code Playgroud)
但文件中还发生了一些其他错误,例如
Object is possibly 'null'.
我不喜欢使用“任何”类型
那么请问您能提供另一种解决方案吗?
有了 Angular 16,我们现在可以使用信号了。
但我似乎不清楚如何简单地推入数组。
该文档来自Angular Signal 官方文档:
当处理包含对象的信号时,直接改变该对象有时很有用。例如,如果对象是数组,您可能希望推送新值而不完全替换数组。要进行这样的内部更改,请使用 .mutate 方法
例如:
messages = signal<Message[]>([]);
ngOnInit(): void {
const newMessage = ...
this.messages.mutate(values => values.push(newMessage));
}
Run Code Online (Sandbox Code Playgroud)
但两次引用该列表似乎很奇怪。第一次与this.messages,第二次与values。
如何将项目推入信号数组?
在下面的模型中,我使用信号作为组件的输入。有用。但我想知道这是否是信号的正确使用。看起来……很奇怪。
以下是维护“我的朋友”列表的服务:
import {
Injectable,
signal
} from '@angular/core';
export interface MyFriend {
name: string;
age: number;
}
@Injectable({
providedIn: 'root'
})
export class MyFriendsService {
myFriends = signal < MyFriend[] > ([{
name: 'Bob',
age: 34,
},
{
name: 'Julie',
age: 30,
},
{
name: 'Martin',
age: 25,
},
]);
}Run Code Online (Sandbox Code Playgroud)
以下是一个好友详细信息组件,显示特定好友的详细信息:
import {
Component,
Input,
computed,
signal
} from '@angular/core';
import {
MyFriend,
MyFriendsService
} from './my-friends.service';
@Component({
selector: 'app-friend-detail',
templateUrl: './friend-detail-component.html',
})
export class FriendDetailComponent {
@Input() …Run Code Online (Sandbox Code Playgroud)与 Constructor 和 ngOnInit 之间的差异相关但不相同。
在 Angular 16 和 17 中,我们现在可以使用takeUntilDestroyed运算符和信号。这两种方法似乎在注入器上下文中效果最好,或者至少具有不需要传递其中一种的优点。
所以问题是(再次)我们应该将初始化放在构造函数(或成员字段)中还是仍然使用OnInit?其次,使用构造函数而不是有任何陷阱吗OnInit?
注意:对于初始化,我的意思是使用httpClient来获取数据以显示在页面上。使用数据映射等设置 RxJS 管道。读取路由参数等。
搁置以下内容:
OnInitorOnChanges@Input()根据旧的 Angular.io 站点的组件生命周期文档:
组件的构造应该便宜且安全。例如,您不应该在组件构造函数中获取数据。您不必担心新组件在测试中创建时或在您决定显示它之前会尝试联系远程服务器。ngOnInit() 是组件获取其初始数据的好地方。
但新的 Angular.dev 站点中不存在此文档。
他们的新教程之一也在构造函数中进行了数据调用:
constructor() {
this.housingService.getAllHousingLocations().then((housingLocationList: HousingLocation[]) => {
this.housingLocationList = housingLocationList;
this.filteredLocationList = housingLocationList;
});
}
Run Code Online (Sandbox Code Playgroud)
Angular 16/17 似乎正朝着在注入上下文(成员字段或构造函数)中完成更多初始化的方向发展。这对性能、稳定性、未来发展有影响吗?
我的组件上有以下简单代码:
import {Component, effect, signal, WritableSignal} from '@angular/core';
import {AppService} from "../app.service";
import {toSignal} from "@angular/core/rxjs-interop";
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
translations: WritableSignal<{data: {}}> = signal({data: []});
constructor( private appService: AppService) {
this.translations = toSignal(this.appService.getTranslations());
effect(() => {
console.log('translation API:', this.translations());
});
}
changeValue(): void {
this.translations.set({data: {hello: 'hallo'}})
}
}
Run Code Online (Sandbox Code Playgroud)
仅供参考:this.appService.getTranslations()返回一个可观察的
我正在尝试 Angular v16 发布的新功能,以及如何将 Observables 转换为 Signals。
我想要对上面的代码做的是,更改 WritableSignal 对象的值并记录更改时的值。
我收到以下错误:
TS2739: Type 'Signal ' is missing the following …Run Code Online (Sandbox Code Playgroud) Angular 16 推出了 Signals 作为开发者预览版。
当我想使用 Signals 时,是否必须关闭 zone.js。如果是这样,Signals 会自动从 zone.js 中完成这项工作吗?
考虑到下面的Angular Signals示例,我对何时应该使用 Signal API(如mutate()和update() )、何时使用 Array API(如forEach)足以触发反应性并更新 UI/模板感到有些困惑?这里有什么区别呢?使用的角度版本:16.0.1
@Component({
selector: 'my-app',
standalone: true,
imports: [CommonModule],
template: `
{{usersList() | json}}
`,
})
export class App {
usersList: Signal<any> = inject(UserService).getUsersList();
constructor() {
}
}
bootstrapApplication(App);
@Injectable({
providedIn: 'root',
})
export class UserService {
private users = signal([
{ id: 1, name: 'Peter', country: 'USA' },
{ id: 2, name: 'Party Boy', country: 'USA' },
{ id: 3, name: 'John Connor', country: 'USA' …Run Code Online (Sandbox Code Playgroud)