Laravel 프로젝트를 진행할때 Livewire 를 적용할것인가에 대해서 잠깐 고민이 생긴다.
Livewire 를 사용하지 않아도 프로젝틀 진행하는데 별다른 어려움이 없는데 말이다. 특히나 Alpine.js 와 항상 찰떡처럼 붙어다니는데 이번 정리글을 통해서 Livewrie 와 Alpine.js 를 확실하게 개념을 잡아보자.
개념잡기
기억 공식: "x는 프론트, wire는 백엔드"
| Alpine.js | x- | 브라우저(프론트엔드) | 브라우저에서 즉시 반응. JS 역할. |
| Livewire | wire- | 서버(백엔드) | 서버와 통신 (Ajax), PHP 메서드 실행 |
x- 로 시작하면 클라이언트에서만 처리한다.
wire: 서버를 한번 갔다 와야 한다.
암기 : wire는 서버로 "전선"을 연결해서 PHP 백엔드에 명령을 보내는 역할.
Alpine.js 예제 코드
<div x-data="{ count: 0 }">
<button @click="count++">+</button>
<span x-text="count"></span>
</div>
@click 은 x-on:click 에 대한 단축 표현식이다.
Livewire 예제 코드
<div>
<button wire:click="increment">+</button>
<span>{{ $count }}</span>
</div>
둘 다 똑같이 보이지만, 하나는 브라우저에서만, 하나는 서버를 거쳐서 작동
wire:click 은 Ajex 를 통해서 백그라운드에서 서버와 통신한다.
입력박스에서 데이타 바인딩 시키기
x-model, wire:model
Alpine.js 예제코드 x-model
<div x-data="{ name: '' }">
<input type="text" x-model="name">
<p>입력한 이름: <span x-text="name"></span></p>
</div>
> JS 변수를 변경시킴. 서버와는 통신하지 않음
Livewire 예제코드 wire:model
<div>
<input type="text" wire:model="name">
<p>입력한 이름: {{ $name }}</p>
</div>
// Livewire 컴포넌트 (PHP 클래스)
class ExampleComponent extends \Livewire\Component {
public $name = '';
public function render() {
return view('livewire.example');
}
}
> Livewire 컴포넌트 속성 $name 과 바인딩 된다.
> 입력할 때마다 Ajax 요청이 발생하고 $name 값이 서버에서 갱신됨
서버에서 받아온 $name 은 입력할때마다 Ajax 를 통해서 통신하기 때문에 UI 반응이 느릴수 있다.
이때 서버에서 한번 받아온 값을 alpine.js 변수로 취급 하고 싶은때는 ?
<div x-data="{ name: @entangle('name') }">
<input type="text" x-model="name">
<p x-text="name"></p>
</div>
class ExampleComponent extends \Livewire\Component {
public $name = '';
}
> @entangle() 를 사용하면 가능하다.
커스컴 이벤트 발생과 수신에 대한 방식과 차이점
Livewire2 와 Livewire3 에서 이벤트 방식이 달라진점이 있다. Livewire2 방식으로 설명한다.
Alpine.js
x-on:click 또는 @click
이벤트 발생 함수 : $dispatch("이벤트명")
@이벤트명.window (전체 이벤트를 수신함. .window 가 없는 경우는 스코프 내에서만 수신함)
<div x-data @my-event.window="alert('이벤트 발생')">
<button @click="$dispatch('my-event')">이벤트 발생</button>
</div>
Livewire
$emit(), $listen, Livewire.on()
$emit() 는 Livewire 에서 이벤트를 발생시키는 함수이다.
-> Livewire 3 에서 $dispatch() 로 변경되었다.
livewire 에서는 $emit()
js 에서는 $wire.emit()
php 에서는 $this->emit()
이벤트를 $emit() 로 발생시키든 $this->emit() 로 발생시키든 JS 에서도 수신가능 하고 Livewire 에서도 수신가능하다.
JS 에서는 Livewire.on() 으로 수신받고 Livewire 에서는 $listeners 에서 수신한다.
livewire -> JS -> listeners -> JS
<!-- 자식 컴포넌트 -->
<button wire:click="$emit('postCreated')">게시물 등록</button>
<!-- 부모 컴포넌트 -->
<script>
Livewire.on('postCreated', () => {
alert('새 게시물이 등록되었습니다!');
});
</script>
또는 내부 컴포넌트에서 처리
class ParentComponent extends \Livewire\Component {
protected $listeners = ['postCreated' => 'refreshList'];
public function refreshList() {
// 목록 갱신
}
}
동시에 사용하는 경우
<div x-data @live-action.window="alert('Alpine이 수신')">
<button wire:click="$emit('live-action')">Livewire에서 이벤트 발생</button>
</div>
> wire:click="$emit()" 대신에 @click="$dispatch()" 를 사용하면 서버와 통신없이 이벤트 처리된다.
> wire:click="$emit()" 는 서버와 통신해서 서버에서 JS 이벤트를 발생시키는 방식이다.
이벤트 처리 3가지 패턴
1. Livewire -> Alpine
Livewire가 $emit()으로 이벤트를 발생시키고, Alpine이 @이벤트.window로 감지하여 처리
<!-- Livewire 컴포넌트 뷰 -->
<div x-data @show-modal.window="open = true" x-init="open = false">
<template x-if="open">
<div class="modal">모달 내용</div>
</template>
</div>
<!-- 버튼 -->
<button wire:click="triggerModal">모달 열기</button>
// Livewire 컴포넌트 메서드
public function triggerModal()
{
$this->dispatchBrowserEvent('show-modal');
}
> dispatchBrowserEvent()는 브라우저에 JS 이벤트 발생 (window.dispatchEvent())
2. Alpine -> Livewire
Alpine이 $dispatch()로 DOM 이벤트를 발생시키고, Livewire가 wire:xxx나 JS로 이벤트 감지
<div x-data>
<button @click="$wire.call('save')">저장</button>
</div>
> $wire.call() 보다는 $wire.emit()
3. JS 브릿지 사용
중간에 JS 함수를 둬서 양쪽 이벤트를 중계 (복잡한 상태 공유 시 사용)
emit() 표현 의미 사용 위치 서버 호출 여부
| $emit() | Livewire의 내부 지시문 | Blade(HTML 속성 내부) | ❌ (JS 수준) |
| $wire.emit() | JavaScript에서 Livewire 호출 | <script> 또는 Alpine | ❌ (JS 수준) |
| $this->emit() | Livewire 컴포넌트(PHP)에서 호출 | Livewire 클래스 내부 | ✅ (서버 실행) |
1. Blade 에서 $emit()
<button wire:click="$emit('postCreated')">Blade 내 이벤트</button>
2. Alpine.js 에서 $wire.emit()
<button x-data @click="$wire.emit('postCreated')">JS 이벤트</button>
3. PHP 에서 this->emit()
public function save() {
$this->emit('postCreated');
}
Livewire3 에서 달라진 Event 방식
| ① 서버 → 브라우저 | dispatchBrowserEvent() | Livewire에서 브라우저로 JS 이벤트 전달 |
| ② 브라우저 → 서버 | @click="$wire.foo()" / @click="$dispatch('my-event')" | Alpine 또는 JS에서 Livewire로 전달 |
| ③ 컴포넌트 간 통신 | dispatch('event-name') + on('event-name') | Livewire 컴포넌트 간 이벤트 송수신 |
Livewire 2 vs 3 이벤트 차이점
| 기능 | Livewire 2 | Livewire 3 |
| $emit, $emitTo | 이벤트 이름 기반 브로드캐스트 | dispatch('event')로 통일 |
| @this.on(...) | 자바스크립트 쪽에서 수신 | on(...)으로 컴포넌트 내 등록 |
| 자식 → 부모 이벤트 | $emit('event') + 부모에서 wire:listen 또는 Livewire.on() | dispatch() + 부모의 on('event') |
| 브라우저 이벤트 | dispatchBrowserEvent('event') | 동일 (유지됨) |
| Alpine 통합 | 복잡한 수신 처리 필요 | Alpine과 쉽게 바인딩 가능 (ex: @livewire('post-created')) |
Livewire 3 와 Apline.js 에서 이벤트 방식의 통일성 제공
Apline.js 에서 직접 Livewire 이벤트 발생시킴.
<button x-data @click="$wire.dispatch('postCreated', { postId: 5 })">
Create
</button>
<button x-data @click="$dispatch('postCreated', {postId: 1})">
// Livewire 컴포넌트에서
#[On('postCreated')]
public function refreshPost($id) {
...
}
$wire.dispatch() 와 $dispatch 는 동일한 작업이다.
하지만 방식의 차이가 있다.
$wire.dipatch()는 livewire 직접호출 방식
$dispatch()는 간접방식
특별하게 다음과 같이 코딩할 수 있다.
use Livewire\Component;
class PostHandler extends Component
{
public function boot()
{
$this->on('postCreated', function ($id) {
logger("Livewire 내부 이벤트 수신. ID: {$id}");
});
}
public function render()
{
return view('livewire.post-handler');
}
}
'Laravel' 카테고리의 다른 글
| Cafe24에서 라라벨 호스팅 방법, php8.4 + composer 설치 (0) | 2025.08.21 |
|---|---|
| Laravel 전용 MCP 서버 - boost (2) | 2025.08.17 |
| Laravel 의 핵심기능 : Service Container와 Service Provider 의 이해 (1) | 2025.08.17 |
| Laravel Pint란? (0) | 2025.03.28 |
| Mailpit - 로컬PC 에서 SMTP 테스트하기 (0) | 2025.02.07 |