skip to content

In Livewire, how do you pass data from a Blade view into a nested component, and when does that component's mount() method run?

level: juniorimportance: must knowfreq 60%

answer

  1. attributes on the component tag
  2. colon prefix for PHP expressions
  3. @livewire('name', [...]) is the same
  4. mount() runs once, at creation
  5. props are not reactive by default

basics

~20 s

Pass props as attributes on <livewire:name /> (a colon prefix evaluates PHP) or in @livewire's array. mount() receives them by parameter name, or matching public properties are filled. mount() runs once, at creation, never on later requests.

solid answer

~50 s

You pass props as tag attributes, `<livewire:stock-level :product="$product" warehouse="north" />`, where a leading colon evaluates a PHP expression and a bare attribute is a string; `@livewire('stock-level', ['product' => $product])` is equivalent, and the tag compiles to it. Livewire calls `mount()` with the props matched **by parameter name**, and if there is no `mount()` it assigns props to public properties of the same name. `mount()` is the component's constructor: it runs **once**, when the component is first rendered, and never again on the requests its actions trigger, so per-request logic belongs in other hooks. Props are **not reactive** by default: if the parent later re-renders with a new value, the child keeps its own copy unless you opt in. In Livewire 4 the tag must be self-closed, because content between an open and close tag is now slot content.

code

php · 18 lines
php
<?php

use App\Models\Product;
use Livewire\Component;

new class extends Component {
    public int $productId;
    public string $warehouse;

    public function mount(Product $product, string $warehouse = 'main'): void
    {
        $this->productId = $product->id;
        $this->warehouse = $warehouse;
    }
};
?>

<div>{{ $warehouse }}: product #{{ $productId }}</div>

go deeper

for a junior

Recall the tag syntax with the colon prefix, the @livewire equivalent, and that mount() receives props by name and runs once.

for a middle

Explain why mount() is skipped on later requests, and how props auto-fill matching properties when there is no mount().

for a senior

Spot bugs from stale props in mounted children and decide when a child should own its state, receive events or opt into reactive props.

for a principal

Set conventions for component boundaries on a dashboard: which data a child receives once at mount and which it must re-derive or subscribe to.

## Two ways to render a nested component A **Livewire component** can be placed inside any Blade view, including another component's template. There are two syntaxes, and the first compiles to the second: ```html <livewire:stock-level :product="$product" warehouse="north" /> @livewire('stock-level', ['product' => $product, 'warehouse' => 'north']) ``` - An attribute with a **leading colon** (`:product`) is evaluated as a PHP expression; a plain attribute (`warehouse="north"`) is passed as a string. - Dots name sub-directories (`<livewire:stock.level />`) and a namespace prefix names a namespaced component (`<livewire:pages::stock.dashboard />`). - In **Livewire 4** the tag must be **self-closed**. Livewire 4 added slots, so an unclosed `<livewire:stock-level>` makes Livewire treat what follows as slot content and the component does not render as intended. - Attributes that do not match a public property (such as `class` or `data-*`) are forwarded to the child's `$attributes` bag instead of becoming props. ## How props arrive: mount() or matching properties Livewire does not call your class's constructor with props. It creates the component and then calls **`mount()`**, matching props to its parameters **by name**: ```php public int $productId; public string $warehouse; public function mount(Product $product, string $warehouse = 'main'): void { $this->productId = $product->id; $this->warehouse = $warehouse; } ``` Parameters can have defaults, and a type-hinted parameter receives the passed object. If a component has **no `mount()`**, Livewire assigns each prop to the public property with the same name, which removes boilerplate for simple cases. Use `mount()` when you need to transform input, derive several properties, or call `$this->fill(...)` with an array such as `$product->only('sku', 'name')`. ## When mount() runs | Moment | Does mount() run? | |---|---| | The parent renders the child for the first time | Yes | | The user clicks a `wire:click` action in the child | No | | The child re-renders after a property update | No | | The parent re-renders and the child is kept | No | `mount()` runs **once per component instance**, on the request that creates it. Every later request rebuilds the component from its snapshot instead of mounting it again. That is why: 1. Values computed in `mount()` must be stored in public properties if later requests need them. 2. Work that must happen on every request (resolving a service, re-checking something) belongs in the per-request lifecycle hooks, not in `mount()`. 3. Values passed in as props are not re-sent on later requests; the component relies on what it stored in its snapshot. ## Props are copies, not live bindings After mounting, the child owns its own copy of each prop. If the parent changes `$product` and re-renders, the child's property **does not** change. Developers coming from front-end frameworks often expect "reactive props" and are surprised. Livewire lets you opt in per property with a dedicated attribute, and components can also talk through events; both are separate topics from mounting. ## A warehouse dashboard example A dashboard lists products and renders one stock-level widget per product: ```html @foreach ($products as $product) <livewire:stock-level :product="$product" wire:key="stock-{{ $product->id }}" /> @endforeach ``` Each widget mounts once with its product. When a user clicks "refresh" inside one widget, only that widget's request runs and `mount()` is skipped; the widget reads state from its own public properties. The `wire:key` gives each child a stable identity so Livewire can match children across re-renders of the loop. ## Props from routes and props from tags The same `mount()` receives input from two places. For a **nested** component, the props come from the tag or `@livewire` array. For a **full-page** component, route parameters are passed to `mount()` by name, and a type-hinted model parameter uses route model binding. Either way, `mount()` sees named values and runs once. ## Common mistakes - Putting initialisation in `__construct()`: Livewire builds components itself, so use `mount()`. - Expecting `mount()` to re-run and refresh data after an action. - Expecting a parent's new value to flow into an already-mounted child. - Leaving a Livewire 4 tag unclosed.

  • What happens if a Livewire component has no mount() method but you pass it props?
    Livewire assigns each prop to the public property with the same name. That covers simple pass-through cases. You still need `mount()` when a prop must be transformed, validated or split into several properties, or when you want a default for a missing prop expressed as a parameter default.
  • Why do Livewire components use mount() instead of the PHP constructor?
    Livewire instantiates components itself on every request, including requests that rebuild a component from its snapshot. A constructor would run each time; `mount()` runs only when the component is first created and receives the props by name, so initialisation happens exactly once.

saying these in an interview costs you the question

  • mount() runs on every request the component handles
  • Changing the parent's value automatically updates the child's prop
  • Props are passed to the component's __construct()
  • Without mount(), props passed to a Livewire component are ignored
  • An unclosed <livewire:x> tag renders the same in Livewire 4 as in v3
  • A component re-reads its props from the tag on every request