ハイドレート
Livewireを使うと、まるでサーバサイドのPHPクラスを直接Webブラウザにアタッチしているように感じられます。ボタンを押すだけでサーバサイドの関数を直接呼び出せるなどの機能が、この錯覚を支えています。しかし実際には、それは単なる錯覚に過ぎません。Using Livewire feels like attaching a server-side PHP class directly to a web browser. Things like calling server-side functions directly from button presses support this illusion. But in reality, it is just that: an illusion.
バックグラウンドでは、Livewireは実際には標準的なWebアプリケーションと非常によく似た動作をします。静的なHTMLをブラウザにレンダリングし、ブラウザのイベントをリッスンし、AJAXリクエストを送信してサーバサイドのコードを呼び出します。In the background, Livewire actually behaves much more like a standard web application. It renders static HTML to the browser, listens for browser events, then makes AJAX requests to invoke server-side code.
Livewireがサーバに送信する各AJAXリクエストは「ステートレス」(コンポーネントの状態を保持する長時間実行されるバックエンドプロセスがないことを意味します)であるため、Livewireは更新を行う前に、コンポーネントの最後に既知の状態を再作成する必要があります。Because each AJAX request Livewire makes to the server is "stateless" (meaning there isn't a long running backend process keeping the state of a component alive), Livewire must re-create the last-known state of a component before making any updates.
Livewireは、サーバサイドの更新を行うたびにPHPコンポーネントの「スナップショット」を作成し、次のリクエストでコンポーネントを再作成または_再開_できるようにします。It does this by taking "snapshots" of the PHP component after each server-side update so that the component can be re-created or resumed on the next request.
このドキュメント全体を通して、スナップショットを作成するプロセスを「dehydration(脱水)」、スナップショットからコンポーネントを再作成するプロセスを「hydration(水和)」と呼びます。Throughout this documentation, we will refer to the process of taking the snapshot as "dehydration" and the process of re-creating a component from a snapshot as "hydration".
Dehydrating(脱水)Dehydrating
Livewireがサーバサイドのコンポーネントを_dehydrate(脱水)_する場合、次の2つのことを行います。When Livewire dehydrates a server-side component, it does two things:
- コンポーネントのテンプレートをHTMLにレンダリングするRenders the component's template to HTML
- コンポーネントのJSONスナップショットを作成するCreates a JSON snapshot of the component
Rendering HTML(HTMLのレンダリング)Rendering HTML
コンポーネントがマウントされた後、または更新が行われた後、Livewireはコンポーネントのrender()メソッドを呼び出して、Bladeテンプレートを生のHTMLに変換します。After a component is mounted or an update has been made, Livewire calls a component's render() method to convert the Blade template to raw HTML.
次のCounterコンポーネントを例に取ります。Take the following Counter component for example:
class Counter extends Component
{
public $count = 1;
public function increment()
{
$this->count++;
}
public function render()
{
return <<<'HTML'
<div>
Count: {{ $count }}
<button wire:click="increment">+</button>
</div>
HTML;
}
}
各マウントまたは更新の後、Livewireは上記のCounterコンポーネントを次のHTMLにレンダリングします。After each mount or update, Livewire would render the above Counter component to the following HTML:
<div>
Count: 1
<button wire:click="increment">+</button>
</div>
The snapshot(スナップショット)The snapshot
次のリクエスト中にサーバ上でCounterコンポーネントを再作成するために、コンポーネントの状態を可能な限りキャプチャしようとして、JSONスナップショットが作成されます。In order to re-create the Counter component on the server during the next request, a JSON snapshot is created, attempting to capture as much of the state of the component as possible:
{
state: {
count: 1,
},
memo: {
name: 'counter',
id: '1526456',
},
}
スナップショットの2つの異なる部分、memoとstateに注目してください。Notice two different portions of the snapshot: memo, and state.
memo部分はコンポーネントを識別して再作成するために必要な情報を格納するために使用され、state部分はコンポーネントのすべてのパブリックプロパティの値を格納します。The memo portion is used to store the information needed to identify and re-create the component, while the state portion stores the values of all the component's public properties.
Info: 上記のスナップショットは、Livewireの実際のスナップショットを凝縮したものです。ライブアプリケーションでは、スナップショットには、検証エラー、子コンポーネントのリスト、ロケールなど、はるかに多くの情報が含まれています。スナップショットオブジェクトの詳細については、snapshot schema documentationを参照してください。[!info] The above snapshot is a condensed version of an actual snapshot in Livewire. In live applications, the snapshot contains much more information, such as validation errors, a list of child components, locales, and much more. For a more detailed look at a snapshot object you may reference the snapshot schema documentation[/docs/javascript#the-snapshot-object].
Embedding the snapshot in the HTML(HTMLへのスナップショットの埋め込み)Embedding the snapshot in the HTML
コンポーネントが最初にレンダリングされると、LivewireはスナップショットをJSONとしてwire:snapshotと呼ばれるHTML属性内に保存します。これにより、LivewireのJavaScriptコアはJSONを抽出し、ランタイムオブジェクトに変換できます。When a component is first rendered, Livewire stores the snapshot as JSON inside an HTML attribute called wire:snapshot. This way, Livewire's JavaScript core can extract the JSON and turn it into a run-time object:
<div wire:id="..." wire:snapshot="{ state: {...}, memo: {...} }">
Count: 1
<button wire:click="increment">+</button>
</div>
Hydrating(水和)Hydrating
コンポーネントの更新がトリガーされた場合、たとえば、Counterコンポーネントで「+」ボタンが押された場合、次のようなペイロードがサーバに送信されます。When a component update is triggered, for example, the "+" button is pressed in the Counter component, a payload like the following is sent to the server:
{
calls: [
{ method: 'increment', params: [] },
],
snapshot: {
state: {
count: 1,
},
memo: {
name: 'counter',
id: '1526456',
},
}
}
Livewireがincrementメソッドを呼び出す前に、最初に新しいCounterインスタンスを作成し、スナップショットの状態をシードする必要があります。Before Livewire can call the increment method, it must first create a new Counter instance and seed it with the snapshot's state.
これは、この結果を実現するPHPの疑似コードです。Here is some PHP pseudo-code that achieves this result:
$state = request('snapshot.state');
$memo = request('snapshot.memo');
$instance = Livewire::new($memo['name'], $memo['id']);
foreach ($state as $property => $value) {
$instance[$property] = $value;
}
上記のスクリプトに従うと、Counterオブジェクトを作成した後、そのパブリックプロパティがスナップショットから提供された状態に基づいて設定されることがわかります。If you follow the above script, you will see that after creating a Counter object, its public properties are set based on the state provided from the snapshot.
Advanced hydration(高度な水和)Advanced hydration
上記のCounterの例は、hydrationの概念を説明するのに適しています。ただし、整数(1)のような単純な値の水和をLivewireがどのように処理するかを示すだけです。The above Counter example works well to demonstrate the concept of hydration; however, it only demonstrates how Livewire handles hydrating simple values like integers (1).
ご存知のように、Livewireは整数以外にも、より洗練されたプロパティタイプを多数サポートしています。As you may know, Livewire supports many more sophisticated property types beyond integers.
もう少し複雑な例を見てみましょう。Todosコンポーネントです。Let's take a look at a slightly more complex example - a Todos component:
class Todos extends Component
{
public $todos;
public function mount() {
$this->todos = collect([
'first',
'second',
'third',
]);
}
}
ご覧のとおり、$todosプロパティを、コンテンツとして3つの文字列を持つLaravel collectionに設定しています。As you can see, we are setting the $todos property to a Laravel collection[https://laravel.com/docs/collections#main-content] with three strings as its content.
JSONだけではLaravelコレクションを表現する方法がないため、Livewireは代わりに、スナップショット内の純粋なデータにメタデータを関連付ける独自のパターンを作成しました。JSON alone has no way of representing Laravel collections, so instead, Livewire has created its own pattern of associating metadata with pure data inside a snapshot.
これは、このTodosコンポーネントのスナップショットの状態オブジェクトです。Here is the snapshot's state object for this Todos component:
state: {
todos: [
[ 'first', 'second', 'third' ],
{ s: 'clctn', class: 'Illuminate\\Support\\Collection' },
],
},
これは、次のようなより簡単なものを期待していた場合、混乱するかもしれません。This may be confusing to you if you were expecting something more straightforward like:
state: {
todos: [ 'first', 'second', 'third' ],
},
ただし、Livewireがこのデータに基づいてコンポーネントをhydrationする場合、それがプレーンな配列ではなくコレクションであることを知る方法はありません。However, if Livewire were hydrating a component based on this data, it would have no way of knowing it's a collection and not a plain array.
したがって、Livewireは、タプル(2つのアイテムの配列)の形式で代替状態構文をサポートしています。Therefore, Livewire supports an alternate state syntax in the form of a tuple (an array of two items):
todos: [
[ 'first', 'second', 'third' ],
{ s: 'clctn', class: 'Illuminate\\Support\\Collection' },
],
Livewireがコンポーネントの状態をhydrationするときにタプルを検出すると、タプルの2番目の要素に格納されている情報を使用して、最初に格納されている状態をよりインテリジェントにhydrationします。When Livewire encounters a tuple when hydrating a component's state, it uses information stored in the second element of the tuple to more intelligently hydrate the state stored in the first.
より明確に示すために、上記のスナップショットに基づいてLivewireがコレクションプロパティを再作成する方法を示す簡略化されたコードを次に示します。To demonstrate more clearly, here is simplified code showing how Livewire might re-create a collection property based on the above snapshot:
[ $state, $metadata ] = request('snapshot.state.todos');
$collection = new $metadata['class']($state);
ご覧のとおり、Livewireは状態に関連付けられたメタデータを使用して、完全なコレクションクラスを導き出します。As you can see, Livewire uses the metadata associated with the state to derive the full collection class.
Deeply nested tuples(深くネストされたタプル)Deeply nested tuples
このアプローチの明確な利点の1つは、深くネストされたプロパティをdehydrateおよびhydrateできることです。One distinct advantage of this approach is the ability to dehydrate and hydrate deeply nested properties.
たとえば、上記のTodosの例を考えてみましょう。コレクションの3番目のアイテムとして、プレーンな文字列の代わりにLaravel Stringableを使用します。For example, consider the above Todos example, except now with a Laravel Stringable[https://laravel.com/docs/helpers#method-str] instead of a plain string as the third item in the collection:
class Todos extends Component
{
public $todos;
public function mount() {
$this->todos = collect([
'first',
'second',
str('third'),
]);
}
}
このコンポーネントの状態のdehydrateされたスナップショットは、次のようになります。The dehydrated snapshot for this component's state would now look like this:
todos: [
[
'first',
'second',
[ 'third', { s: 'str' } ],
],
{ s: 'clctn', class: 'Illuminate\\Support\\Collection' },
],
ご覧のとおり、コレクションの3番目のアイテムは、メタデータタプルにdehydrateされています。タプルの最初の要素はプレーンな文字列値であり、2番目の要素は、この文字列が_stringable_であることをLivewireに示すフラグです。As you can see, the third item in the collection has been dehydrated into a metadata tuple. The first element in the tuple being the plain string value, and the second being a flag denoting to Livewire that this string is a stringable.
Supporting custom property types(カスタムプロパティタイプのサポート)Supporting custom property types
内部的には、Livewireは最も一般的なPHPおよびLaravelタイプのhydrationをサポートしています。ただし、サポートされていないタイプをサポートする場合は、Synthesizers — プリミティブ以外のプロパティタイプをhydrate/dehydrateするためのLivewireの内部メカニズム — を使用してこれを行うことができます。Internally, Livewire has hydration support for the most common PHP and Laravel types. However, if you wish to support un-supported types, you can do so using Synthesizers[/docs/synthesizers] — Livewire's internal mechanism for hydrating/dehydrating non-primitive property types.