Skip to content

Commit 0181a01

Browse files
authored
fix: translate signals (angular#938)
1 parent b049c92 commit 0181a01

File tree

10 files changed

+891
-512
lines changed

10 files changed

+891
-512
lines changed

.textlintrc

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
},
2121
"no-doubled-joshi": {
2222
"allow": [
23-
"の"
23+
"の",
24+
"が",
25+
"に"
2426
]
2527
},
2628
"no-exclamation-question-mark": false,
+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# シグナル入力
2+
3+
シグナル入力を使用すると、親コンポーネントから値をバインドできます。
4+
これらの値は `Signal` を使用して公開され、コンポーネントのライフサイクル中に変化する可能性があります。
5+
6+
役に立つ情報: シグナル入力は現在、[開発者プレビュー](/reference/releases#developer-preview)にあります。
7+
8+
Angularは、2種類の入力をサポートしています。
9+
10+
**オプション入力**
11+
`input.required` を使用しない限り、入力はデフォルトでオプショナルです。
12+
明示的な初期値を指定できます。指定しない場合、Angularは暗黙的に `undefined` を使用します。
13+
14+
**必須入力**
15+
必須入力は常に、指定された入力タイプの値を持ちます。
16+
`input.required` 関数を使用して宣言されます。
17+
18+
```typescript
19+
import {Component, input} from '@angular/core';
20+
21+
@Component({...})
22+
export class MyComp {
23+
// オプション
24+
firstName = input<string>(); // InputSignal<string|undefined>
25+
age = input(0); // InputSignal<number>
26+
27+
// 必須
28+
lastName = input.required<string>(); // InputSignal<string>
29+
}
30+
```
31+
32+
クラスメンバーのイニシャライザーとして `input` または `input.required` 関数を使用すると、Angularは自動的に入力を認識します。
33+
34+
## 入力に別名をつける
35+
36+
Angularは、クラスメンバー名を入力の名前として使用します。
37+
別名を使用すると、公開名を変更できます。
38+
39+
```typescript
40+
class StudentDirective {
41+
age = input(0, {alias: 'studentAge'});
42+
}
43+
```
44+
45+
これにより、ユーザーは `[studentAge]` を使用して入力にバインドできます。一方、コンポーネント内では `this.age` を使用して入力値にアクセスできます。
46+
47+
## テンプレートでの使用
48+
49+
シグナル入力は、読み取り専用のシグナルです。
50+
`signal()` を使用して宣言されたシグナルと同様に、入力シグナルを呼び出すことで、入力の現在の値にアクセスできます。
51+
52+
```html
53+
<p>First name: {{firstName()}}</p>
54+
<p>Last name: {{lastName()}}</p>
55+
```
56+
57+
この値へのアクセスは、リアクティブなコンテキストでキャプチャされ、入力値が変更されるたびに、Angular自身などのアクティブなコンシューマーに通知できます。
58+
59+
実際には、入力シグナルは、[シグナルガイド](guide/signals)で知られているシグナルの単純な拡張です。
60+
61+
```typescript
62+
export class InputSignal<T> extends Signal<T> { ... }`.
63+
```
64+
65+
## 値の派生
66+
67+
シグナルと同様に、`computed` を使用して入力から値を派生できます。
68+
69+
```typescript
70+
import {Component, input, computed} from '@angular/core';
71+
72+
@Component({...})
73+
export class MyComp {
74+
age = input(0);
75+
76+
// 年齢を 2 倍した値。
77+
ageMultiplied = computed(() => this.age() * 2);
78+
}
79+
```
80+
81+
算出シグナルは、値をメモ化します。
82+
詳細については、[計算されたシグナルに関するセクション](guide/signals#computed-signals)を参照してください。
83+
84+
## 変更の監視
85+
86+
シグナル入力を使用すると、ユーザーは `effect` 関数を利用できます。
87+
この関数は、入力が変更されるたびに実行されます。
88+
89+
次の例を考えてみましょう。
90+
`firstName` 入力が変更されるたびに、新しい値がコンソールに出力されます。
91+
92+
```typescript
93+
import {input, effect} from '@angular/core';
94+
95+
class MyComp {
96+
firstName = input.required<string>();
97+
98+
constructor() {
99+
effect(() => {
100+
console.log(this.firstName());
101+
});
102+
}
103+
}
104+
```
105+
106+
`console.log` 関数は、`firstName` 入力が変更されるたびに呼び出されます。
107+
これは、`firstName` が使用可能になった直後と、`MyComp` のライフサイクル中の後続の変更に対して発生します。
108+
109+
## 値の変換
110+
111+
入力の値を、その意味を変更せずに、強制変換または解析したい場合があります。
112+
変換は、親テンプレートからの生の値を、期待される型に変換します。
113+
変換は、[純粋関数](https://en.wikipedia.org/wiki/Pure_function)である必要があります。
114+
115+
```typescript
116+
class MyComp {
117+
disabled = input(false, {
118+
transform: (value: boolean|string) => typeof value === 'string' ? value === '' : value,
119+
});
120+
}
121+
```
122+
123+
上記の例では、`disabled` という名前の入力を宣言しています。この入力は、`boolean` 型と `string` 型の値を受け入れます。
124+
これは、`transform` オプションの `value` の明示的なパラメーター型によってキャプチャされます。
125+
これらの値は、変換によって `boolean` に解析され、`boolean` になります。
126+
127+
このように、`this.disabled()` を呼び出す際に、コンポーネント内では `boolean` のみを使用できます。一方、コンポーネントのユーザーは、空の文字列を省略記号として渡して、コンポーネントを無効にできます。
128+
129+
```html
130+
<my-custom-comp disabled>
131+
```
132+
133+
重要: 入力の意味を変更する場合、または[不純な](https://en.wikipedia.org/wiki/Pure_function#Impure_functions)関数の場合は、変換を使用しないでください。
134+
代わりに、意味が異なる変換には `computed` を、入力が変更されるたびに実行されるべき不純なコードには `effect` を使用してください。
135+
136+
## なぜシグナル入力を使用すべきなのか、`@Input()` を使用すべきではないのか
137+
138+
シグナル入力は、デコレーターベースの `@Input()` のリアクティブな代替手段です。
139+
140+
デコレーターベースの `@Input` と比較して、シグナル入力は多くの利点があります。
141+
142+
1. シグナル入力は、より**型安全**です。
143+
<br/>• 必須入力は、初期値や、入力に常に値があることをTypeScriptに伝えるためのトリックを必要としません。
144+
<br/>• 変換は、受け入れられた入力値と一致するように自動的にチェックされます。
145+
2. テンプレートで使用されるシグナル入力は、`OnPush` コンポーネントを**自動的に**ダーティにします。
146+
3. 入力が変更されるたびに、`computed` を使用して簡単に値を**派生**できます。
147+
4. `ngOnChanges` やセッターの代わりに、`effect` を使用することで、入力の監視が簡単になり、より局所的になります。
+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# モデル入力
2+
3+
**モデル入力** は、コンポーネントが新しい値を別のコンポーネントに伝播できるようにする、
4+
特殊な入力です。
5+
6+
HELPFUL: モデル入力は現在 [開発者プレビュー](/reference/releases#developer-preview) です。
7+
8+
コンポーネントを作成するときは、普通の入力を作成する方法と同様に、
9+
モデル入力を定義できます。
10+
11+
```typescript
12+
import {Component, model, input} from '@angular/core';
13+
14+
@Component({...})
15+
export class CustomCheckbox {
16+
// これはモデル入力です。
17+
checked = model(false);
18+
19+
// これは普通の入力です。
20+
disabled = input(false);
21+
}
22+
```
23+
24+
2種類の入力はどちらも、値をプロパティにバインドすることを可能にします。
25+
ただし、**モデル入力を使用すると、コンポーネントの作者はプロパティに値を書き込むことができます**
26+
27+
その他の点では、モデル入力を普通の入力と同じように使用できます。
28+
`computed``effect` などのリアクティブコンテキストを含め、シグナル関数を呼び出して値を読み取ることができます。
29+
30+
```typescript
31+
import {Component, model, input} from '@angular/core';
32+
33+
@Component({
34+
selector: 'custom-checkbox',
35+
template: '<div (click)="toggle()"> ... </div>',
36+
})
37+
export class CustomCheckbox {
38+
checked = model(false);
39+
disabled = input(false);
40+
41+
toggle() {
42+
// 普通の入力は読み取り専用ですが、モデル入力には直接書き込むことができます。
43+
this.checked.set(!this.checked());
44+
}
45+
}
46+
```
47+
48+
コンポーネントがモデル入力に新しい値を書き込むと、
49+
Angularはその入力に値をバインドしているコンポーネントに新しい値を伝播できます。
50+
これは、値が双方向に流れるため、**双方向バインディング** と呼ばれます。
51+
52+
## シグナルによる双方向バインディング
53+
54+
書き込み可能なシグナルをモデル入力にバインドできます。
55+
56+
```typescript
57+
@Component({
58+
...,
59+
// `checked` はモデル入力です。
60+
// 括弧内角括弧構文(別名「バナナインボックス」)は、双方向バインディングを作成します。
61+
template: '<custom-checkbox [(checked)]="isAdmin" />',
62+
})
63+
export class UserProfile {
64+
protected isAdmin = signal(false);
65+
}
66+
```
67+
68+
上記の例では、`CustomCheckbox``checked` モデル入力に値を書き込むことができ、
69+
その値は `UserProfile``isAdmin` シグナルに伝播されます。
70+
このバインディングにより、`checked``isAdmin` の値が同期されます。
71+
バインディングは `isAdmin` シグナル自体を渡し、シグナルの __ は渡さないことに注意してください。
72+
73+
## プレーンなプロパティによる双方向バインディング
74+
75+
プレーンなJavaScriptプロパティをモデル入力にバインドできます。
76+
77+
```typescript
78+
@Component({
79+
...,
80+
// `checked` はモデル入力です。
81+
// 括弧内角括弧構文(別名「バナナインボックス」)は、双方向バインディングを作成します。
82+
template: '<custom-checkbox [(checked)]="isAdmin" />',
83+
})
84+
export class UserProfile {
85+
protected isAdmin = false;
86+
}
87+
```
88+
89+
上記の例では、`CustomCheckbox``checked` モデル入力に値を書き込むことができ、
90+
その値は `UserProfile``isAdmin` プロパティに伝播されます。
91+
このバインディングにより、`checked``isAdmin` の値が同期されます。
92+
93+
## 暗黙的な `change` イベント
94+
95+
コンポーネントまたはディレクティブでモデル入力を宣言すると、
96+
Angularはそのモデルに対応する [出力](guide/components/outputs) を自動的に作成します。
97+
出力の名前は、モデル入力の名前の後に「Change」が付加されたものです。
98+
99+
```typescript
100+
@Directive({...})
101+
export class CustomCheckbox {
102+
// これは、自動的に「checkedChange」という名前の出力を作成します。
103+
// テンプレートで `(checkedChange)="handler()"` を使用して購読できます。
104+
checked = model(false);
105+
}
106+
```
107+
108+
`set` または `update` メソッドを呼び出してモデル入力に新しい値を書き込むたびに、
109+
Angularはこの変更イベントを発行します。
110+
111+
## モデル入力のカスタマイズ
112+
113+
普通の入力と同様に、モデル入力を必須としてマークしたり、
114+
別名を提供したりできます。
115+
116+
モデル入力は、入力の変換をサポートしていません。
117+
118+
## `model()``input()` の違い
119+
120+
`input()``model()` の両方の関数は、Angularで信号ベースの入力を定義する方法ですが、
121+
いくつかの違いがあります。
122+
1. `model()` は、**入力と出力の両方** を定義します。
123+
出力の名前は常に、双方向バインディングをサポートするために、入力名に `Change` が付加されたものです。
124+
ディレクティブの利用者は、入力のみ、出力のみ、または両方を使用するかを決定します。
125+
2. `ModelSignal``WritableSignal` であり、
126+
`set` メソッドと `update` メソッドを使用して、どこからでも値を変更できます。
127+
新しい値が割り当てられると、`ModelSignal` は出力にイベントを発行します。
128+
これは、読み取り専用で、テンプレートを通じてのみ変更できる `InputSignal` とは異なります。
129+
3. モデル入力は入力変換をサポートしませんが、信号入力はサポートします。
130+
131+
## いつモデル入力を使用すべきか
132+
133+
ユーザーの操作に基づいて値を変更するために存在するコンポーネントでモデル入力を使用します。
134+
日付ピッカーやコンボボックスなどのカスタムフォームコントロールは、
135+
主要な値にモデル入力を使用する必要があります。
136+
137+
ローカルな状態を保持するための追加のクラスプロパティを導入することを避けるための便宜として、
138+
モデル入力を使用しないでください。

0 commit comments

Comments
 (0)