コンポーネントのネスト
Livewireでは親コンポーネントの中に、さらにLivewireコンポーネントをネストすることができます。この機能は、アプリケーション全体で共有するLivewireコンポーネント内で動作を再利用したり、カプセル化したりできるため、非常に強力です。Livewire allows you to nest additional Livewire components inside of a parent component. This feature is immensely powerful, as it allows you to re-use and encapsulate behavior within Livewire components that are shared across your application.
Bladeコンポーネントを作成することをお勧めします。コンポーネントがLivewireの動的な性質から恩恵を受ける場合、または直接的なパフォーマンス上の利点がある場合にのみ、Livewireコンポーネントを作成してください。[!warning] You might not need a Livewire component Before you extract a portion of your template into a nested Livewire component, ask yourself: Does this content in this component need to be "live"? If not, we recommend that you create a simple Blade component[https://laravel.com/docs/blade#components] instead. Only create a Livewire component if the component benefits from Livewire's dynamic nature or if there is a direct performance benefit.
Warning! Livewireコンポーネントが必要ない場合もあります: テンプレートの一部をネストしたLivewireコンポーネントへ抽出する前に、自問してください。このコンポーネントのコンテンツは「リアルタイム反映」である必要があるか?もしそうでないなら、代わりに単純な
ネストしたLivewireコンポーネントのパフォーマンス、使用上の注意点、および制約に関する詳細は、Livewireコンポーネントのネストに関する詳細な技術的考察を参照してください。Consult our in-depth, technical examination of Livewire component nesting[/docs/understanding-nesting] for more information on the performance, usage implications, and constraints of nested Livewire components.
コンポーネントのネストNesting a component
Livewireコンポーネントを親コンポーネント内でネストするには、親コンポーネントのBladeビューに含めるだけです。以下は、ネストしたTodoList
コンポーネントを含むDashboard
親コンポーネントの例です。To nest a Livewire component within a parent component, simply include it in the parent component's Blade view. Below is an example of a Dashboard
parent component that contains a nested TodoList
component:
<?php
namespace App\Livewire;
use Livewire\Component;
class Dashboard extends Component
{
public function render()
{
return view('livewire.dashboard');
}
}
<div>
<h1>Dashboard</h1>
<livewire:todo-list /> <!-- [tl! highlight] -->
</div>
このページの初期レンダリングでは、Dashboard
コンポーネントは<livewire:todo-list />
を検出し、その場でレンダーします。Dashboard
への後続のネットワークリクエストでは、ネストしたtodo-list
コンポーネントはレンダーをスキップします。なぜなら、それは現在、ページ上の独立したコンポーネントになっているからです。ネストとレンダーの背後にある技術的な概念の詳細については、すべてのコンポーネントが「独立」である理由に関するドキュメントを参照してください。On this page's initial render, the Dashboard
component will encounter <livewire:todo-list />
and render it in place. On a subsequent network request to Dashboard
, the nested todo-list
component will skip rendering because it is now its own independent component on the page. For more information on the technical concepts behind nesting and rendering, consult our documentation on why nested components are "islands"[/docs/understanding-nesting#every-component-is-an-island].
コンポーネントのレンダー構文の詳細については、コンポーネントのレンダーに関するドキュメントを参照してください。For more information about the syntax for rendering components, consult our documentation on Rendering Components[/docs/components#rendering-components].
子へのプロップの受け渡しPassing props to children
親コンポーネントから子コンポーネントへのデータの受け渡しは簡単です。実際、一般的なBladeコンポーネントでプロップを渡すのとよく似ています。Passing data from a parent component to a child component is straightforward. In fact, it's very much like passing props to a typical Blade component[https://laravel.com/docs/blade#components].
たとえば、TodoList
コンポーネントが$todos
のコレクションをTodoCount
という子コンポーネントに渡す例を見てみましょう。For example, let's check out a TodoList
component that passes a collection of $todos
to a child component called TodoCount
:
<?php
namespace App\Livewire;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class TodoList extends Component
{
public function render()
{
return view('livewire.todo-list', [
'todos' => Auth::user()->todos,
]);
}
}
<div>
<livewire:todo-count :todos="$todos" />
<!-- ... -->
</div>
ご覧のとおり、:$todos="$todos"
という構文でtodo-count
に$todos
を渡しています。As you can see, we are passing $todos
into todo-count
with the syntax: :todos="$todos"
.
$todos
を子コンポーネントへ渡したので、子コンポーネントのqmount()
メソッドによりデータを受け取れます。Now that $todos
has been passed to the child component, you can receive that data through the child component's mount()
method:
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Todo;
class TodoCount extends Component
{
public $todos;
public function mount($todos)
{
$this->todos = $todos;
}
public function render()
{
return view('livewire.todo-count', [
'count' => $this->todos->count(),
]);
}
}
Tip: 短縮形として
mount()
を省略する: 上記の例のmount()
メソッドが冗長な定型コードのように感じる場合は、プロパティ名とパラメータ名が一致する場合に限り、省略できます。[!tip] Omitmount()
as a shorter alternative If themount()
method in above example feels like redundant boilerplate code to you, it can be omitted as long as the property and parameter names match:public $todos; // [tl! highlight]
静的プロップの受け渡しPassing static props
前の例では、Livewireの動的なプロップ構文を使用して、子コンポーネントへプロップを渡しました。これは、次のようなPHP式をサポートします。In the previous example, we passed props to our child component using Livewire's dynamic prop syntax, which supports PHP expressions like so:
<livewire:todo-count :todos="$todos" />
しかし、文字列などの単純な静的値をコンポーネントへ渡したい場合があるでしょう。そのような場合は、ステートメントの先頭からコロンを省略できます。However, sometimes you may want to pass a component a simple static value such as a string. In these cases, you may omit the colon from the beginning of the statement:
<livewire:todo-count :todos="$todos" label="Todo Count:" />
論理値は、キーのみを指定することでコンポーネントへ提供できます。たとえば、値がtrue
の$inline
変数をコンポーネントに渡すには、単にコンポーネントタグにinline
を配置します。Boolean values may be provided to components by only specifying the key. For example, to pass an $inline
variable with a value of true
to a component, we may simply place inline
on the component tag:
<livewire:todo-count :todos="$todos" inline />
短縮された属性構文Shortened attribute syntax
PHP変数をコンポーネントへ渡す場合、変数名とプロップ名が同じであることがよくあります。名前を2回書くのを避けられるように、Livewireでは、変数にコロンを付けるだけで済みます。When passing PHP variables into a component, the variable name and the prop name are often the same. To avoid writing the name twice, Livewire allows you to simply prefix the variable with a colon:
<livewire:todo-count :todos="$todos" /> <!-- [tl! remove] -->
<livewire:todo-count :$todos /> <!-- [tl! add] -->
ループ中の子のレンダーRendering children in a loop
ループ内で子コンポーネントをレンダーする場合は、各繰り返しで一意のkey
値を含める必要があります。When rendering a child component within a loop, you should include a unique key
value for each iteration.
コンポーネントキーは、特にコンポーネントが既にレンダーされている場合や、複数のコンポーネントがページ上で再配置される場合に、Livewireが後続のレンダーで各コンポーネントを追跡する方法です。Component keys are how Livewire tracks each component on subsequent renders, particularly if a component has already been rendered or if multiple components have been re-arranged on the page.
子コンポーネントにkey
を設定するには、子コンポーネントにkey
プロップを指定します。You can specify the component's key by specifying a :key
prop on the child component:
<div>
<h1>Todos</h1>
@foreach ($todos as $todo)
<livewire:todo-item :$todo :key="$todo->id" />
@endforeach
</div>
ご覧のとおり、各子コンポーネントには、各$todo
のIDを一意のキーとしてセットしています。これにより、todoが並べ替えられても、キーが一意であり、追跡可能だと保証されます。As you can see, each child component will have a unique key set to the ID of each $todo
. This ensures the key will be unique and tracked if the todos are re-ordered.
[!warning] Keys aren't optional If you have used frontend frameworks like Vue or Alpine, you are familiar with adding a key to a nested element in a loop. However, in those frameworks, a key isn't mandatory, meaning the items will render, but a re-order might not be tracked properly. However, Livewire relies more heavily on keys and will behave incorrectly without them.
Warning! キーはオプションではありません: VueやAlpineのようなフロントエンドフレームワークを使用したことがある場合は、ループ内のネストされた要素にキーを追加することに慣れているでしょう。ただし、これらのフレームワークでは、キーは必須ではありません。つまり、アイテムはレンダーされますが、並べ替えで正しく追跡されない可能性があります。しかしながら、Livewireはキーに大きく依存しており、キーがないと正しく動作しません。
リアクティブなプロップReactive props
Livewireを初めて使用する開発者は、プロップがデフォルトで「リアクティブ」であると期待します。言い換えれば、親が子コンポーネントに渡たすプロップの値を変更すると、子コンポーネントは自動的に更新されると期待しています。しかし、Livewireのプロップは、デフォルトでリアクティブでありません。Developers new to Livewire expect that props are "reactive" by default. In other words, they expect that when a parent changes the value of a prop being passed into a child component, the child component will automatically be updated. However, by default, Livewire props are not reactive.
Livewireを使用するとき、すべてのコンポーネントは独立しています。つまり、親が更新をトリガーし、ネットワークリクエストをディスパッチすると、親コンポーネントの状態のみをサーバへ送信し、再レンダーします。子コンポーネントの状態は送信しません。この動作の背後にある意図は、サーバとクライアントの間でやり取りするデータの量を最小限に抑え、更新を可能な限りパフォーマンスが高くなるようにするためです。When using Livewire, every component is an island[/docs/understanding-nesting#every-component-is-an-island]. This means that when an update is triggered on the parent and a network request is dispatched, only the parent component's state is sent to the server to re-render - not the child component's. The intention behind this behavior is to only send the minimal amount of data back and forth between the server and client, making updates as performant as possible.
ただし、プロップをリアクティブにしたい場合、またはリアクティブにする必要がある場合は、#[Reactive]
属性パラメータを使用して、この動作を簡単に有効にできます。But, if you want or need a prop to be reactive, you can easily enable this behavior using the #[Reactive]
attribute parameter.
たとえば、以下は親TodoList
コンポーネントのテンプレートです。内部では、TodoCount
コンポーネントをレンダリングし、現在のtodoリストを渡しています。For example, below is the template of a parent TodoList
component. Inside, it is rendering a TodoCount
component and passing in the current list of todos:
<div>
<h1>Todos:</h1>
<livewire:todo-count :$todos />
<!-- ... -->
</div>
次に、TodoCount
コンポーネントの$todos
プロップへ、#[Reactive]
を追加しましょう。これにより、親コンポーネント内で追加または削除したtodoは、TodoCount
コンポーネント内で自動的に更新をトリガーします。Now let's add #[Reactive]
to the $todos
prop in the TodoCount
component. Once we have done so, any todos that are added or removed inside the parent component will automatically trigger an update within the TodoCount
component:
<?php
namespace App\Livewire;
use Livewire\Attributes\Reactive;
use Livewire\Component;
use App\Models\Todo;
class TodoCount extends Component
{
#[Reactive] // [tl! highlight]
public $todos;
public function render()
{
return view('livewire.todo-count', [
'count' => $this->todos->count(),
]);
}
}
リアクティブなプロパティは非常に強力な機能であり、LivewireをVueやReactのようなフロントエンドコンポーネントライブラリに近づけます。ただし、この機能のパフォーマンスへの影響を理解し、特定のシナリオに適合する場合にのみ#[Reactive]
を追加することが重要です。Reactive properties are an incredibly powerful feature, making Livewire more similar to frontend component libraries like Vue and React. But, it is important to understand the performance implications of this feature and only add #[Reactive]
when it makes sense for your particular scenario.
wire:model
を使用した子データの結合Binding to child data using wire:model
親コンポーネントと子コンポーネント間で状態を共有するためのもう1つの強力なパターンは、LivewireのModelable
機能を介して、子コンポーネントで直接wire:model
を使用することです。Another powerful pattern for sharing state between parent and child components is using wire:model
directly on a child component via Livewire's Modelable
feature.
この動作は、入力要素を専用のLivewireコンポーネントに抽出しつつ、親コンポーネントでその状態にアクセスする必要がある場合、とても一般的です。This behavior is very commonly needed when extracting an input element into a dedicated Livewire component while still accessing its state in the parent component.
以下は、ユーザーが追加しようとしている現在のtodoを追跡する$todo
プロパティを含む親TodoList
コンポーネントの例です。Below is an example of a parent TodoList
component that contains a $todo
property which tracks the current todo about to be added by a user:
<?php
namespace App\Livewire;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use App\Models\Todo;
class TodoList extends Component
{
public $todo = '';
public function add()
{
Todo::create([
'content' => $this->pull('todo'),
]);
}
public function render()
{
return view('livewire.todo-list', [
'todos' => Auth::user()->todos,
]);
}
}
TodoList
テンプレート中でわかるように、wire:model
は$todo
プロパティをネストしたTodoInput
コンポーネントへ直接結合するために使用しています。As you can see in the TodoList
template, wire:model
is being used to bind the $todo
property directly to a nested TodoInput
component:
<div>
<h1>Todos</h1>
<livewire:todo-input wire:model="todo" /> <!-- [tl! highlight] -->
<button wire:click="add">Add Todo</button>
<div>
@foreach ($todos as $todo)
<livewire:todo-item :$todo :key="$todo->id" />
@endforeach
</div>
</div>
Livewireは、子コンポーネントの任意のプロパティへ追加できる#[Modelable]
属性を提供し、親コンポーネントからモデル化可能にします。Livewire provides a #[Modelable]
attribute you can add to any child component property to make it modelable from a parent component.
以下は、#[Modelable]
属性を$value
プロパティへ追加したTodoInput
コンポーネントです。これにより、親によりコンポーネントにwire:model
が宣言されている場合、このプロパティを結合する必要があることをLivewireへ通知します。Below is the TodoInput
component with the #[Modelable]
attribute added above the $value
property to signal to Livewire that if wire:model
is declared on the component by a parent it should bind to this property:
<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\Modelable;
class TodoInput extends Component
{
#[Modelable] // [tl! highlight]
public $value = '';
public function render()
{
return view('livewire.todo-input');
}
}
<div>
<input type="text" wire:model="value" >
</div>
これで、親TodoList
コンポーネントは、TodoInput
を他の入力要素のように扱い、wire:model
を使用してその値に直接結合できます。Now the parent TodoList
component can treat TodoInput
like any other input element and bind directly to its value using wire:model
.
Warning! 現在、Livewireは単一の
#[Modelable]
属性のみをサポートしているため、最初に指定した属性のみ結合します。[!warning] Currently Livewire only supports a single#[Modelable]
attribute, so only the first one will be bound.
子コンポーネントからのイベントのリスニングListening for events from children
親子コンポーネント間の通信におけるもう一つの強力な手法は、Livewireのイベントシステムです。これは、サーバまたはクライアント上でイベントを発行し、他のコンポーネントがそれをインターセプトできるようにするものです。Another powerful parent-child component communication technique is Livewire's event system, which allows you to dispatch an event on the server or client that can be intercepted by other components.
Livewireのイベントシステムに関する完全なドキュメントでは、イベントに関するより詳細な情報を提供していますが、以下では、イベントを使用して親コンポーネントの更新をトリガーする簡単な例について説明します。Our complete documentation on Livewire's event system[/docs/events] provides more detailed information on events, but below we'll discuss a simple example of using an event to trigger an update in a parent component.
Todoを表示および削除する機能を持つ、TodoList
コンポーネントを考えてみましょう。Consider a TodoList
component with functionality to show and remove todos:
<?php
namespace App\Livewire;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use App\Models\Todo;
class TodoList extends Component
{
public function remove($todoId)
{
$todo = Todo::find($todoId);
$this->authorize('delete', $todo);
$todo->delete();
}
public function render()
{
return view('livewire.todo-list', [
'todos' => Auth::user()->todos,
]);
}
}
<div>
@foreach ($todos as $todo)
<livewire:todo-item :$todo :key="$todo->id" />
@endforeach
</div>
子コンポーネントTodoItem
内からremove()
を呼び出すには、#[On]
属性を使用して、TodoList
へイベントリスナを追加します。To call remove()
from inside the child TodoItem
components, you can add an event listener to TodoList
via the #[On]
attribute:
<?php
namespace App\Livewire;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use App\Models\Todo;
use Livewire\Attributes\On;
class TodoList extends Component
{
#[On('remove-todo')] // [tl! highlight]
public function remove($todoId)
{
$todo = Todo::find($todoId);
$this->authorize('delete', $todo);
$todo->delete();
}
public function render()
{
return view('livewire.todo-list', [
'todos' => Auth::user()->todos,
]);
}
}
属性をアクションへ追加すると、TodoList
の子コンポーネントから、remove-todo
イベントを発行できます。Once the attribute has been added to the action, you can dispatch the remove-todo
event from the TodoList
child component:
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Todo;
class TodoItem extends Component
{
public Todo $todo;
public function remove()
{
$this->dispatch('remove-todo', todoId: $this->todo->id); // [tl! highlight]
}
public function render()
{
return view('livewire.todo-item');
}
}
<div>
<span>{{ $todo->content }}</span>
<button wire:click="remove">Remove</button>
</div>
これで、TodoItem
内の"Remove"ボタンをクリックすると、親のTodoList
コンポーネントは、その発行されたイベントをインターセプトし、todoの削除を実行します。Now when the "Remove" button is clicked inside a TodoItem
, the parent TodoList
component will intercept the dispatched event and perform the todo removal.
親でそのtodoを削除すると、リストを再レンダーし、remove-todo
イベントを発行した子がページから削除されます。After the todo is removed in the parent, the list will be re-rendered and the child that dispatched the remove-todo
event will be removed from the page.
クライアント側でディスパッチすることでパフォーマンスを向上させるImproving performance by dispatching client-side
上記の例は機能しますが、単一のアクションを実行するために2つのネットワークリクエストが必要です。Though the above example works, it takes two network requests to perform a single action:
TodoItem
コンポーネントからの最初のネットワークリクエストは、remove
アクションをトリガーし、remove-todo
イベントを発行します。The first network request from theTodoItem
component triggers theremove
action, dispatching theremove-todo
event.- 2番目のネットワークリクエストは、
remove-todo
イベントがクライアント側でディスパッチされた後であり、TodoList
がremove
アクションを呼び出すためにインターセプトします。The second network request is after theremove-todo
event is dispatched client-side and is intercepted byTodoList
to call itsremove
action.
remove-todo
イベントをクライアント側で直接ディスパッチすることで、最初のリクエストを完全に回避できます。以下は、remove-todo
イベントをディスパッチするときにネットワークリクエストをトリガーしないように更新したTodoItem
コンポーネントです。You can avoid the first request entirely by dispatching the remove-todo
event directly on the client-side. Below is an updated TodoItem
component that does not trigger a network request when dispatching the remove-todo
event:
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Todo;
class TodoItem extends Component
{
public Todo $todo;
public function render()
{
return view('livewire.todo-item');
}
}
<div>
<span>{{ $todo->content }}</span>
<button wire:click="$dispatch('remove-todo', { todoId: {{ $todo->id }} })">Remove</button>
</div>
原則として、可能な限りクライアント側でのディスパッチを常に優先してください。As a rule of thumb, always prefer dispatching client-side when possible.
子から親への直接アクセスDirectly accessing the parent from the child
イベント通信は、間接層を追加します。 親は子がディスパッチしないイベントをリッスンでき、子は親がインターセプトしないイベントをディスパッチできます。Event communication adds a layer of indirection. A parent can listen for an event that never gets dispatched from a child, and a child can dispatch an event that is never intercepted by a parent.
この間接性は望ましい場合もあります。ただし場合によっては、子コンポーネントから親コンポーネントへ直接アクセスするのが好ましい場合があります。This indirection is sometimes desirable; however, in other cases you may prefer to access a parent component directly from the child component.
Livewireでは、Bladeテンプレートに$parent
マジック変数を提供しており、これで実現できます。これを使用し、子からアクションとプロパティへ直接アクセスできます。$parent
マジック変数を介し、親のremove()
アクションを直接呼び出すように書き換えた、上記のTodoItem
テンプレートを以下に示します。Livewire allows you to accomplish this by providing a magic $parent
variable to your Blade template that you can use to access actions and properties directly from the child. Here's the above TodoItem
template rewritten to call the remove()
action directly on the parent via the magic $parent
variable:
<div>
<span>{{ $todo->content }}</span>
<button wire:click="$parent.remove({{ $todo->id }})">Remove</button>
</div>
イベントと親コンポーネントの直接通信は、親子コンポーネントの間でやり取りするための方法です。これらのトレードオフを理解することで、特定のシナリオで使用するパターンについて、より多くの情報に基づいた決定を下すことができます。Events and direct parent communication are a few of the ways to communicate back and forth between parent and child components. Understanding their tradeoffs enables you to make more informed decisions about which pattern to use in a particular scenario.
動的な子コンポーネントDynamic child components
場合によっては、実行時までページにレンダリングする必要のある子コンポーネントがわからない場合があります。そのためLivewireでは、:is
プロップを受け取る<livewire:dynamic-component ...>
を介し、実行時に子コンポーネントを選択できるようにしています。Sometimes, you may not know which child component should be rendered on a page until run-time. Therefore, Livewire allows you to choose a child component at run-time via <livewire:dynamic-component ...>
, which receives an :is
prop:
<livewire:dynamic-component :is="$current" />
動的な子コンポーネントは、さまざまなシナリオで役立ちますが、以下は動的なコンポーネントを使用してマルチステップフォームで各ステップをレンダーする例です。Dynamic child components are useful in a variety of different scenarios, but below is an example of rendering different steps in a multi-step form using a dynamic component:
<?php
namespace App\Livewire;
use Livewire\Component;
class Steps extends Component
{
public $current = 'step-one';
protected $steps = [
'step-one',
'step-two',
'step-three',
];
public function next()
{
$currentIndex = array_search($this->current, $this->steps);
$this->current = $this->steps[$currentIndex + 1];
}
public function render()
{
return view('livewire.todo-list');
}
}
<div>
<livewire:dynamic-component :is="$current" :key="$current" />
<button wire:click="next">Next</button>
</div>
Steps
コンポーネントの$current
プロップが"step-one"に設定されている場合、Livewireは以下のような"step-one"という名前のコンポーネントをレンダーします。Now, if the Steps
component's $current
prop is set to "step-one", Livewire will render a component named "step-one" like so:
<?php
namespace App\Livewire;
use Livewire\Component;
class StepOne extends Component
{
public function render()
{
return view('livewire.step-one');
}
}
好みに応じ、以下の代替構文も使用できます。If you prefer, you can use the alternative syntax:
<livewire:is :component="$current" :key="$current" />
Warning! 各子コンポーネントに一意のキーを割り当てることを忘れないでください。Livewireは自動的に
<livewire:dynamic-child />
および<livewire:is />
のキーを生成しますが、同じキーがすべての子コンポーネントに適用されるため、後続のレンダーをスキップします。[!warning] Don't forget to assign each child component a unique key. Although Livewire automatically generates a key for<livewire:dynamic-child />
and<livewire:is />
, that same key will apply to all your child components, meaning subsequent renders will be skipped.キーがコンポーネントのレンダーでどのように影響するかをより深く理解するには、子コンポーネントの再レンダーの強制を参照してください。See forcing a child component to re-render[#forcing-a-child-component-to-re-render] for a deeper understanding of how keys affect component rendering.
再帰的コンポーネントRecursive components
ほとんどのアプリケーションではめったに必要ありませんが、Livewireコンポーネントは再帰的にネストできます。つまり、親コンポーネントはそれ自体を子としてレンダーできます。Although rarely needed by most applications, Livewire components may be nested recursively, meaning a parent component renders itself as its child.
サブの質問を自分自身に添付できる、SurveyQuestion
コンポーネントを含むアンケートを想像してみてください。Imagine a survey which contains a SurveyQuestion
component that can have sub-questions attached to itself:
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Question;
class SurveyQuestion extends Component
{
public Question $question;
public function render()
{
return view('livewire.survey-question', [
'subQuestions' => $this->question->subQuestions,
]);
}
}
<div>
Question: {{ $question->content }}
@foreach ($subQuestions as $subQuestion)
<livewire:survey-question :question="$subQuestion" :key="$subQuestion->id" />
@endforeach
</div>
Warning! もちろん、再帰的なコンポーネントには、再帰の標準的なルールが適用されます。最も重要なことは、テンプレートが無限に再帰しないようにするために、テンプレートにロジックを含める必要があるということです。上記の例では、
$subQuestion
にオリジナルの質問が独自の$subQuestion
として含まれている場合、無限ループが発生します。[!warning] Of course, the standard rules of recursion apply to recursive components. Most importantly, you should have logic in your template to ensure the template doesn't recurse indefinitely. In the example above, if a$subQuestion
contained the original question as its own$subQuestion
, an infinite loop would occur.
子コンポーネントの再レンダーの強制Forcing a child component to re-render
Livewireはバックグラウンドで、テンプレート内のネストされた各Livewireコンポーネントのキーを生成します。Behind the scenes, Livewire generates a key for each nested Livewire component in its template.
たとえば、ネストした以下のtodo-count
コンポーネントについて考えてみましょう。For example, consider the following nested todo-count
component:
<div>
<livewire:todo-count :$todos />
</div>
Livewireは内部的に、以下のようにランダムな文字列キーをコンポーネントに付与します。Livewire internally attaches a random string key to the component like so:
<div>
<livewire:todo-count :$todos key="lska" />
</div>
親コンポーネントをレンダーし、上記のような子コンポーネントに遭遇すると、親にアタッチした子のリストへキーを保存します。When the parent component is rendering and encounters a child component like the above, it stores the key in a list of children attached to the parent:
'children' => ['lska'],
Livewireはこのリストを、子コンポーネントが前のリクエストで既にレンダーしたかを検出するため、後続のレンダーで参照します。既にレンダーしていた場合、そのコンポーネントをスキップします。ネストしたコンポーネントは独立していることを思い出してください。ただし、子のキーがリストにない場合、つまり未レンダーの場合、Livewireはそのコンポーネントの新しいインスタンスを作成し、その場所にレンダーします。Livewire uses this list for reference on subsequent renders in order to detect if a child component has already been rendered in a previous request. If it has already been rendered, the component is skipped. Remember, nested components are islands[/docs/understanding-nesting#every-component-is-an-island]. However, if the child key is not in the list, meaning it hasn't been rendered already, Livewire will create a new instance of the component and render it in place.
こうしたニュアンスはすべて、ほとんどのユーザーが意識する必要のない舞台裏の動作です。ですが、子にキーを設定するという概念は、子のレンダーを制御するための強力なツールです。These nuances are all behind-the-scenes behavior that most users don't need to be aware of; however, the concept of setting a key on a child is a powerful tool for controlling child rendering.
この知識を利用して、コンポーネントを強制的に再レンダーしたい場合は、単にキーを変更するだけです。Using this knowledge, if you want to force a component to re-render, you can simply change its key.
以下は、$todos
がコンポーネントへ渡す際に変更された場合に、todo-count
コンポーネントを破棄して再初期化したい場合の例です。Below is an example where we might want to destroy and re-initialize the todo-count
component if the $todos
being passed to the component are changed:
<div>
<livewire:todo-count :todos="$todos" :key="$todos->pluck('id')->join('-')" />
</div>
上記のように、$todos
の内容に基づいて動的な:key
文字列を生成しています。このようにして、todo-count
コンポーネントは、$todos
自体が変更されるまで、通常どおりにレンダーされ、存在します。その時点で、コンポーネントは完全に最初から再初期化され、古いコンポーネントは破棄されます。As you can see above, we are generating a dynamic :key
string based on the content of $todos
. This way, the todo-count
component will render and exist as normal until the $todos
themselves change. At that point, the component will be re-initialized entirely from scratch, and the old component will be discarded.