Introduction
Livewire components don't live for a single page load — they are serialized to the browser, re-hydrated on every interaction, and can re-render many times. Lifecycle hooks let you run code at precise moments in that cycle, and computed properties let you derive values without hammering the database on every render.
Key Concepts
- Mount: Runs once when the component is first instantiated. Use it to accept parameters and set initial state.
- Hydrate / Dehydrate: Run before/after the component is serialized to and from the browser on each round trip.
- Updating / Updated: Run before and after a public property changes via
wire:model. The most common place to validate or react to input. - Computed Property: A method decorated with
#[Computed]that Livewire evaluates lazily and caches for the duration of a single request.
Real World Context
Without computed properties, accessing $this->posts inside a render() method and again inside a child template runs two identical database queries per interaction. On a busy dashboard that's the difference between 50ms and 500ms round trips.
Deep Dive
The Lifecycle in Order
Here's what happens when a user types in a wire:model.live input:
- Browser sends the new value to the server.
- Livewire instantiates the component class.
hydrate()runs (if defined), rebuilding state from the serialized payload.updating('search')runs before the property is updated — throw an exception from here to abort the update.- The public
$searchproperty is updated. updated('search')runs.render()returns the updated HTML.dehydrate()runs before the component is re-serialized.- The server sends the HTML diff back to the browser.
Mount vs Constructor
The mount() method replaces the PHP constructor for Livewire components. It receives route parameters and initial data:
phpuse Livewire\Component; use App\Models\Post; class EditPost extends Component { public Post $post; public string $title = ''; public function mount(Post $post): void { $this->post = $post; $this->title = $post->title; } public function render() { return view('livewire.edit-post'); } }
Mount only runs once per component lifetime — not on every AJAX round trip. Subsequent requests rehydrate $post and $title automatically from the serialized payload.
Reacting to Property Changes
The updating and updated hooks fire on every property write via wire:model:
phppublic function updating(string $name, mixed $value): void { // Validate any field as it changes if ($name === 'email') { $this->validateOnly('email'); } } public function updatedSearch(string $value): void { // Hook for a single specific property $this->resetPage(); // Reset pagination when search changes }
Naming the method updatedSearch targets only the $search property — a cleaner pattern than inspecting the $name argument.
Computed Properties
A computed property runs lazily and caches its result for the current request:
phpuse Livewire\Attributes\Computed; class UserDashboard extends Component { #[Computed] public function recentPosts() { return auth()->user()->posts() ->latest() ->limit(5) ->get(); } public function render() { return view('livewire.user-dashboard'); } }
In the Blade template:
blade<ul> @foreach ($this->recentPosts as $post) <li>{{ $post->title }}</li> @endforeach </ul>
Access the property via $this->recentPosts in the template or PHP — the first call runs the query, every subsequent call returns the cached result. When a new request arrives (e.g. the user types a character), the cache resets and the query runs exactly once.
Common Pitfalls
- Heavy work inside
render()— The render method runs on every round trip. Anything expensive should move to a computed property or be triggered by a specific action. - Mutating state inside
updating()—updatingruns before the property is set. If you modify$this->searchhere, your change is overwritten. Useupdated()for post-update logic. - Forgetting that
mountdoesn't re-run — Users will tell you the route param vanished after an interaction. The fix is to put logic inmountthat restores state frompublicproperties, not to fetch it fresh every request.
Best Practices
- Prefer per-property hooks —
updatedSearch()is clearer than inspecting$namein a genericupdated()method. - Use
#[Computed]for derived data — If a value is always derived from other properties, make it computed. Livewire caches it per request automatically. - Keep
mountfocused on initialization — Set state, load fixtures, nothing more. Complex logic belongs in actions.
Summary
mountruns once at component creation;hydrate/dehydratewrap every round trip.updating($name)/updated($name)react to property writes;updatedXtargets a single property.- Computed properties (
#[Computed]) cache derived values for the current request. - Keep
render()lean — move heavy queries into computed properties or actions.