skip to content

Components & Properties

Livewire components pair a PHP class with a Blade view, in one single file or split across several. Interviewers check which property types survive a round trip and when #[Computed] reruns.

on this pageshow

explore

questions

6

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
open as a page

In a Livewire component, what does the #[Computed] attribute do, and when does the method behind it run again?

level: middleimportance: must knowfreq 55%

basics

~20 s

#[Computed] turns a Livewire method into a property memoized for one request: the first $this->name read runs it, later reads reuse the result. Each new request runs it again on first read; unset() busts it, persist: true caches across requests.

open as a page

In Livewire 4, what does php artisan make:livewire create by default, and how do the sfc, mfc and class component formats differ?

level: juniorimportance: should knowfreq 50%

basics

~20 s

In Livewire 4, make:livewire creates a single-file component by default: one ⚡-prefixed .blade.php file holding an anonymous component class above its Blade markup. --mfc splits it into a directory of files; --class makes the v3-style class plus separate view.

open as a page

In Livewire 4, how do you serve a component as a full page with Route::livewire, and how does #[Layout] choose the page's layout?

level: middleimportance: should knowfreq 40%

basics

~20 s

Route::livewire('/stock', 'pages::stock.dashboard') registers a GET route that renders the component inside a layout. The layout is config livewire.component_layout (layouts::app) unless #[Layout('...')] on the class or ->layout() in render() overrides it; route parameters reach mount() by name.

open as a page

In a Livewire component, which types can a public property hold, and why can't a protected property keep state between requests?

level: middleimportance: should knowfreq 45%

basics

~20 s

Livewire public properties must survive a JSON round trip: primitives and arrays, BackedEnum, Collection, Eloquent models and collections, DateTime/Carbon and Stringable, or a Wireable class. Protected properties are never sent, so each request starts them from their declared default.

open as a page

A Livewire stock-level widget keeps an Eloquent collection of products in a public property; what does that cost on every update, and how would you restructure it?

level: seniorimportance: should knowfreq 30%

basics

~20 s

A public Eloquent collection is dehydrated to class and keys, then reloaded by key on later requests without its select(), eager loads or global scopes. Keep scalar filters public, move the list to #[Computed], and persist only arrays on Laravel 13.

open as a page