Skip to content

docs: Translate Advanced Guides > Reactivity in Depth #70

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 22, 2020
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 39 additions & 38 deletions src/guide/reactivity.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
# Reactivity in Depth
# リアクティブの探求

Now it’s time to take a deep dive! One of Vue’s most distinct features is the unobtrusive reactivity system. Models are proxied JavaScript objects. When you modify them, the view updates. It makes state management simple and intuitive, but it’s also important to understand how it works to avoid some common gotchas. In this section, we are going to dig into some of the lower-level details of Vue’s reactivity system.
さらに深く見ていきましょう!Vue の最大の特徴の 1 つは、控えめなリアクティブシステムです。モデルはプロキシされた JavaScript オブジェクトです。それらを変更するとビューが更新されます。これは状態管理を非常にシンプルかつ直感的にしますが、よくある問題を避けるためにその仕組みを理解することも重要です。このセクションでは、Vue のリアクティブシステムに関する低レベルの詳細のいくつかを掘り下げていきます。

## What is Reactivity?
<VideoLesson href="https://www.vuemastery.com/courses/vue-3-reactivity/vue3-reactivity" title="Learn how how reactivity works in depth with Vue Mastery">Vue Mastery のリアクティブの探求に関する無料ビデオを視聴する</VideoLesson>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[memo]
この部分は 2020/09/18 に追加された下記の2コミットへの対応です。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます!


This term comes up in programming quite a bit these days, but what do people mean when they say it? Reactivity is a programming paradigm that allows us to adjust to changes in a declarative manner. The canonical example that people usually show, because it’s a great one, is an excel spreadsheet.
# リアクティブとは何か?

この言葉はここ最近のプログラミングで頻繁に目にしますが、それについて言及される時どういう意味で使われているでしょうか?リアクティブは宣言的な方法で変更に対応できるようにするプログラミングのパラダイムです。優れているが故に、標準的な例としてしばしば上げられるのが Excel のスプレッドシートです。

<video width="550" height="400" controls>
<source src="/images/reactivity-spreadsheet.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>

If you put the number two in the first cell, and the number 3 in the second and asked for the SUM, the spreadsheet would give it to you. No surprises there. But if you update that first number, the SUM automagically updates too.
最初のセルに数字の 2 を入力し、2 番目のセルに数字の 3 を入力して SUM を要求すると、スプレッドシートは SUM の結果を返してくれます。なんの驚きもありません。ただし、最初のセルの数字を更新すると、 SUM の結果もなんと自動的に更新されます。

JavaScript doesn’t usually work like this -- If we were to write something comparable in JavaScript:
JavaScript は通常このように機能しません。JavaScript で同等のものを書こうとしたら次のようになります:

```js
var val1 = 2
Expand All @@ -29,17 +31,17 @@ val1 = 3
// 5
```

If we update the first value, the sum is not adjusted.
最初の値を更新しても、合計値は調整されません。

So how would we do this in JavaScript?
では、 JavaScript を使って以下の要素をどうやって実現するのでしょうか。

- Detect when there’s a change in one of the values
- Track the function that changes it
- Trigger the function so it can update the final value
- いずれかの値に変化があった時に検出する
- それを変更する関数を追跡する
- 最終的な値を更新できるように関数を発火させる

## How Vue Tracks These Changes
## Vue がこれらの変更を追跡する方法

When you pass a plain JavaScript object to an application or component instance as its `data` option, Vue will walk through all of its properties and convert them to [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) using a handler with getters and setters. This is an ES6-only feature, but we offer a version of Vue 3 that uses the older `Object.defineProperty` to support IE browsers. Both have the same surface API, but the Proxy version is slimmer and offers improved performance.
プレーンな JavaScript オブジェクトを `data` オプションとしてアプリケーションまたはコンポーネントインスタンスに渡すと、Vue はそのすべてのプロパティを走査して、ゲッターとセッターのハンドラを使用しそれらを[プロキシ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Proxy)に変換します。 これは ES6 のみの機能ですが、旧式の `Object.defineProperty` を使用した Vue 3 のバージョンを IE ブラウザをサポートするために提供しています。どちらも表面的には同じ API を提供しますが、プロキシバージョンの方がよりスリムで、パフォーマンスが改良されています。

<div class="reactivecontent">
<iframe height="500" style="width: 100%;" scrolling="no" title="Proxies and Vue's Reactivity Explained Visually" src="https://codepen.io/sdras/embed/zYYzjBg?height=500&theme-id=light&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
Expand All @@ -48,9 +50,9 @@ When you pass a plain JavaScript object to an application or component instance
</iframe>
</div>

That was rather quick and requires some knowledge of [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) to understand! So let’s dive in a bit. There’s a lot of literature on Proxies, but what you really need to know is that a **Proxy is an object that encases another object or function and allows you to intercept it.**
この例はかなり素早いので、理解するには[プロキシ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Proxy)についての知識がある程度必要です!では、少し詳しく見ていきましょう。プロキシに関する文献はたくさんありますが、本当に知っておく必要があることは **プロキシは別のオブジェクトまたは関数を包み、操作を差し込むこと(intercept)ができるオブジェクトだということです。**

We use it like this: `new Proxy(target, handler)`
proxy は次のように使用します: `new Proxy(target, handler)`

```js
const dinner = {
Expand All @@ -69,7 +71,7 @@ console.log(proxy.meal)
// tacos
```

Ok, so far, we’re just wrapping that object and returning it. Cool, but not that useful yet. But watch this, we can also intercept this object while we wrap it in the Proxy. This interception is called a trap.
今のところは、オブジェクトをラップしてそれをそのまま返すだけです。かっこいいですが、まだ役に立つ物ではありません。しかしこれを見てください。プロキシでラップしている中で、このオブジェクトに操作を差し込むこともできます。この操作の差し込みはトラップと呼ばれています。

```js
const dinner = {
Expand All @@ -90,9 +92,9 @@ console.log(proxy.meal)
// tacos
```

Beyond a console log, we could do anything here we wish. We could even _not_ return the real value if we wanted to. This is what makes Proxies so powerful for creating APIs.
コンソールログ以外にも、ここでは思い通りの操作が可能です。必要な場合は、実際の値を返さ _ない_ ようにすることさえできます。これにより、プロキシは API の作成において強力なものになっています。

Furthermore, there’s another feature Proxies offer us. Rather than just returning the value like this: `target[prop]`, we could take this a step further and use a feature called `Reflect`, which allows us to do proper `this` binding. It looks like this:
さらに、プロキシは別の機能も提供してくれます。`target[prop]` のような値をただ返すだけではなく、これをさらに一歩進めて `this` のバインディングを適切に行うことができる `Reflect` と呼ばれる機能を使用することができます。これは次のようになります。

```js{7}
const dinner = {
Expand All @@ -112,7 +114,7 @@ console.log(proxy.meal)
// tacos
```

We mentioned before that in order to have an API that updates a final value when something changes, we’re going to have to set new values when something changes. We do this in the handler, in a function called `track`, where we pass in the `target` and `key`.
前述の通り、何らかの変更があった時に最終的な値を更新する API を実装するには、何らかの変更があった時に新しい値を設定する必要があるでしょう。この処理をハンドラー内の `track` という関数で、 `target` `key` を引数として渡して行います。

```js{7}
const dinner = {
Expand All @@ -133,7 +135,7 @@ console.log(proxy.meal)
// tacos
```

Finally, we also set new values when something changes. For this, we’re going to set the changes on our new proxy, by triggering those changes:
最後に、何らかの変更があった時に新しい値を設定します。このために、これらの変更を発火させることで、新しいプロキシに変更をセットします。

```js
const dinner = {
Expand All @@ -158,19 +160,19 @@ console.log(proxy.meal)
// tacos
```

Remember this list from a few paragraphs ago? Now we have some answers to how Vue handles these changes:
数段落前のこのリストを覚えていますか?これで Vue がこれらの変更を処理する方法に対するいくつかの回答が出揃いました。

- <strike>Detect when there’s a change in one of the values</strike>: we no longer have to do this, as Proxies allow us to intercept it
- **Track the function that changes it**: We do this in a getter within the proxy, called `effect`
- **Trigger the function so it can update the final value**: We do in a setter within the proxy, called `trigger`
- <strike>いずれかの値に変化があった時に検出する</strike>: プロキシがそれに対する操作の差し込みを可能にしているため、その必要がなくなりました
- **それを変更する関数を追跡する**: これは、 `effect` と呼ばれるプロキシ内のゲッターで行います
- **最終的な値を更新できるように関数を発火させる**: `trigger` と呼ばれるプロキシ内のセッターで行います

The proxied object is invisible to the user, but under the hood they enable Vue to perform dependency-tracking and change-notification when properties are accessed or modified. As of Vue 3, our reactivity is now available in a [separate package](https://github.com/vuejs/vue-next/tree/master/packages/reactivity). One caveat is that browser consoles format differently when converted data objects are logged, so you may want to install [vue-devtools](https://github.com/vuejs/vue-devtools) for a more inspection-friendly interface.
プロキシされたオブジェクトはユーザーには見えませんが、内部的にはプロパティがアクセスまたは変更されたときに、Vue が依存関係の追跡と変更通知を実行できるようになっています。 Vue 3 以降、リアクティブは[個別のパッケージ](https://github.com/vuejs/vue-next/tree/master/packages/reactivity)で利用できるようになりました。注意点の 1 つは、変換されたデータオブジェクトがログに記録された時は、ブラウザコンソールが違った整形をすることです。そのため、 [vue-devtools](https://github.com/vuejs/vue-devtools) をインストールして、より見やすいインターフェイスにすることをお勧めします。

### Proxied Objects
## プロキシされたオブジェクト

Vue internally tracks all objects that have been made reactive, so it always returns the same proxy for the same object.
Vue はリアクティブに作られたすべてのオブジェクトを内部的に追跡するため、常に同じオブジェクトに対して同じプロキシを返します。

When a nested object is accessed from a reactive proxy, that object is _also_ converted into a proxy before being returned:
ネストされたオブジェクトがリアクティブプロキシからアクセスされると、次のようにそのオブジェクト _も_ 返却される前にプロキシに変換されます:

```js
const handler = {
Expand All @@ -187,9 +189,9 @@ const handler = {
}
```

### Proxy vs. original identity
## プロキシとオリジナルの同一性

The use of Proxy does introduce a new caveat to be aware with: the proxied object is not equal to the original object in terms of identity comparison (`===`). For example:
プロキシを使用使うことにより、警戒すべき新しい注意点が発生します。プロキシ化されたオブジェクトは、同一性比較 (===) の点で元のオブジェクトと等しくないということです。 例えば:

```js
const obj = {}
Expand All @@ -198,20 +200,19 @@ const wrapped = new Proxy(obj, handlers)
console.log(obj === wrapped) // false
```

The original and the wrapped version will behave the same in most cases, but be aware that they will fail
operations that rely on strong identity comparisons, such as `.filter()` or `.map()`. This caveat is unlikely to come up when using the options API, because all reactive state is accessed from `this` and guaranteed to already be proxies.
オリジナルとラップされたバージョンはほとんどの場合同じように動作しますが、 `.filter()` や `.map()` などの強力な同一性比較に依存する操作は失敗することに注意してください。オプション API を使用する場合、この注意点に出くわすことはほとんどありません。すべてのリアクティブな状態が `this` からアクセスされ、すでにプロキシだということが保証されているためです。

However, when using the composition API to explicitly create reactive objects, the best practice is to never hold a reference to the original raw object and only work with the reactive version:
しかし、コンポジション API を使用して明示的にリアクティブオブジェクトを作成する場合、元の生のオブジェクトへの参照を保持せず、次のようにリアクティブバージョンでのみ処理をすることがベストプラクティスです:

```js
const obj = reactive({
count: 0
}) // no reference to original
```

## Watchers
## ウォッチャ

Every component instance has a corresponding watcher instance, which records any properties "touched" during the component’s render as dependencies. Later on when a dependency’s setter is triggered, it notifies the watcher, which in turn causes the component to re-render.
すべてのコンポーネントインスタンスには対応するウォッチャインスタンスがあり、コンポーネントのレンダリング中に「触れられた」プロパティを依存関係として記録します。後に依存関係にあるもののセッターが発火されると、ウォッチャーに通知され、コンポーネントが再レンダリングされます。

<div class="reactivecontent">
<iframe height="500" style="width: 100%;" scrolling="no" title="Second Reactivity with Proxies in Vue 3 Explainer" src="https://codepen.io/sdras/embed/GRJZddR?height=500&theme-id=light&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
Expand All @@ -220,10 +221,10 @@ Every component instance has a corresponding watcher instance, which records any
</iframe>
</div>

When you pass an object to a component instance as data, Vue converts it to a proxy. This proxy enables Vue to perform dependency-tracking and change-notification when properties are accessed or modified. Each property is considered a dependency.
オブジェクトをデータとしてコンポーネントインスタンスに渡すと、Vue はそれをプロキシに変換します。このプロキシにより、Vue はプロパティがアクセスまたは変更されたときに、依存関係の追跡と変更通知の実行ができるようになります。各プロパティは依存関係と見なされます。

After the first render, a component would have tracked a list of dependencies &mdash; the properties it accessed during the render. Conversely, the component becomes a subscriber to each of these properties. When a proxy intercepts a set operation, the property will notify all of its subscribed components to re-render.
最初のレンダリングの後、コンポーネントはレンダリング中にアクセスしたプロパティを依存関係一覧として追跡します。逆に言えば、コンポーネントはこれらの各プロパティのサブスクライバーになります。プロキシがセット処理を傍受すると、プロパティはサブスクライブされているすべてのコンポーネントに再レンダリングを通知します。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subscribersubscribed も訳 + 意訳して以下のようにしておいてください! 🙏

Suggested change
最初のレンダリングの後、コンポーネントはレンダリング中にアクセスしたプロパティを依存関係一覧として追跡します。逆に言えば、コンポーネントはこれらの各プロパティのサブスクライバーになります。プロキシがセット処理を傍受すると、プロパティはサブスクライブされているすべてのコンポーネントに再レンダリングを通知します
最初のレンダリングの後、コンポーネントはレンダリング中にアクセスしたプロパティを依存関係一覧として追跡します。逆に言えば、コンポーネントはこれらの各プロパティの値を監視する購読者になります。プロキシがセット処理を傍受すると、プロパティは購読されているすべてのコンポーネントに再レンダリングを通知します

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビューありがとうございます!以下のコミットで対応いたしました。
dc2300b


[//]: # 'TODO: Insert diagram'

> If you are using Vue 2.x and below, you may be interested in some of the change detection caveats that exist for those versions, [explored in more detail here](change-detection.md).
> Vue 2.x 以前を使用している場合は、それらのバージョンに存在する変更検出の注意点に興味があるかもしれません[詳細はこちらをご覧ください](change-detection.md)