최근 Livewire 3를 사용하면서 Alpine.js와 함께 이벤트를 주고받는 구조를 설계하는 경우가 많습니다.
특히 모달, 토스트, 폼 CRUD 등에서 Livewire와 JS 간의 데이터 흐름을 정확히 이해해야 불필요한 오류를 줄이고 유지보수가 쉬워집니다.
이번 글에서는 Livewire ↔ JS 간 이벤트 통신 구조와 데이터 타입 처리 방식을 단계별로 정리합니다.
1. Livewire의 $this->dispatch()는 두 가지 역할을 한다
Livewire v3의 dispatch() 메서드는 단일 함수지만, 송신 방향에 따라 동작이 달라집니다.
구분 설명
| Livewire 이벤트 | 다른 Livewire 컴포넌트로 서버 내부에서 전달 |
| 브라우저 이벤트 | JS/Alpine으로 클라이언트 이벤트 전송 |
// Livewire 간 통신 (다른 컴포넌트로)
$this->dispatch('userUpdated')->to(UserList::class);
// 브라우저(JS/Alpine)로 전송
$this->dispatch('toast', message: '저장되었습니다.');
2. JS/Alpine이 이벤트 수신 방식
브라우저 이벤트는 window.dispatchEvent()로 전파되며,
Alpine에서는 x-on:event.window로 바로 수신할 수 있습니다.
<div x-on:toast.window="alert($event.detail.message)">
<!-- Livewire에서 보낸 'toast' 이벤트 수신 -->
</div>
여기서 $event.detail 객체는 PHP에서 보낸 데이터가 그대로 들어옵니다.
예를 들어 다음 코드를 Livewire에서 실행하면,
$this->dispatch('toast', type: 'success', message: '저장되었습니다.');
Alpine에서 e.detail 값은 다음과 같습니다.
{ type: "success", message: "저장되었습니다." }
3. 데이터 전달 형식 (Livewire → JS)
Livewire에서 브라우저로 보낼 수 있는 데이터는 JSON 직렬화가 가능한 타입만 허용됩니다.
PHP 타입 JS 변환 형태 가능 여부
| string, int, float, bool, array, null | 그대로 전달 | ✅ 가능 |
| object, Model, Collection, Carbon | 직렬화 불가 | ❌ 불가능 |
즉, 모델 객체를 직접 보낼 수 없습니다.
필요한 정보(ID, 이름, 상태 등)만 단순화해서 전달해야 합니다.
// 올바른 예시
$this->dispatch('toast', message: '완료', id: $user->id);
// 잘못된 예시
$this->dispatch('toast', user: $user); // ❌ Model은 직렬화 불가
4. Livewire 간 이벤트 전달 (->to())
서버 컴포넌트 간 데이터 전달은 JSON이 아닌 PHP 객체로 처리되므로,
Eloquent 모델이나 복잡한 배열도 그대로 전달할 수 있습니다.
// UsersTable → UserForm
$this->dispatch('user-selected', id: $user->id)->to(UserForm::class);
// UserForm
#[On('user-selected')]
public function loadUser($id)
{
$this->user = User::find($id);
}
이 방식은 서버 내부에서 동작하기 때문에
브라우저 직렬화 제약이 없고 PHP 객체 그대로 전달됩니다.
5. 반대로 JS → Livewire로 이벤트 보내기
JS에서는 다음과 같이 Livewire 이벤트를 직접 발생시킬 수 있습니다.
Livewire.dispatch('user-selected', { id: 123, name: '홍길동' });
Livewire에서는 #[On('user-selected')]로 수신할 수 있습니다.
#[On('user-selected')]
public function loadUser($id, $name)
{
$this->userId = $id;
$this->userName = $name;
}
매개변수 전달 규칙
JS 전송 PHP 수신 결과
| { id: 1, name: "홍길동" } | $id = 1, $name = '홍길동' |
| [1, "홍길동"] | $id = 1, $name = '홍길동' |
| { foo: {a: 1, b: 2} } | $foo = ['a' => 1, 'b' => 2] |
6. JS → Livewire에서 발생하는 대표적인 에러와 해결
(1) Date 객체
Livewire.dispatch('start', { date: new Date() }); // ❌
→ 직렬화 불가능하므로 ISO8601 문자열로 변환해야 합니다.
Livewire.dispatch('start', { date: new Date().toISOString() }); // ✅
(2) 숫자/불리언이 문자열로 전달됨
JS에서는 "1", "true" 형태로 넘어가 PHP 타입 충돌이 발생할 수 있습니다.
Livewire.dispatch('update', { id: Number(id), active: Boolean(active) });
(3) 파일/Blob 객체
직렬화 불가.
Livewire 업로드 기능을 사용하거나 파일 메타데이터만 이벤트로 전달해야 합니다.
7. JS → Livewire 전송 시 안전한 패턴
1) JS 전처리
function toPayload(obj) {
return JSON.parse(JSON.stringify(obj, (k, v) => {
if (v instanceof Date) return v.toISOString();
if (typeof v === 'function' || typeof v === 'undefined') return null;
return v;
}));
}
Livewire.dispatch('order:update', toPayload({ id: 10, qty: 2 }));
2) PHP 검증
#[On('order:update')]
public function update(array $payload)
{
$data = validator($payload, [
'id' => 'required|integer|min:1',
'qty' => 'required|integer|min:1',
])->validate();
Order::find($data['id'])->update(['qty' => $data['qty']]);
}
8. 브라우저 이벤트와 Livewire 이벤트의 비교 요약
| 구분 | 브라우저 이벤트 | Livewire 이벤트 |
| 전송 메서드 | $this->dispatch() | $this->dispatch()->to() |
| 수신자 | JS / Alpine | Livewire 컴포넌트 |
| 직렬화 | JSON | PHP 객체 그대로 |
| 데이터 제한 | 단순 타입만 | 객체, 모델 가능 |
| 반응 | 즉시 UI 반응 | 리렌더링 발생 |
| 사용 예 | 토스트, 모달, 알림 | CRUD, 상태 갱신 |
9. 결론
- $this->dispatch()는 하나의 함수로 두 가지 이벤트 채널을 통합 지원한다.
- JS ↔ Livewire 간 통신은 JSON 직렬화 가능한 단순 데이터만 전달해야 한다.
- 복잡한 데이터는 ID나 메타데이터로 대체하고, 서버에서 재조회하는 방식이 안정적이다.
- 이벤트 네임스페이스를 명확히 구분(toast:*, form:*, user:*)하면 충돌을 방지할 수 있다.
- 타입 불일치 문제는 JS 전처리 + PHP 검증으로 해결한다.
참고 문서
정리 요약
Livewire와 Alpine.js 간의 이벤트 통신은 구조적으로 단순하지만,
직렬화 규칙과 타입 제약을 명확히 이해해야 안정적으로 작동합니다.
“서버-컴포넌트 간은 PHP 객체, 브라우저와는 JSON” 이 원칙만 기억해두면
Livewire 기반의 모든 복합 UI를 예측 가능하게 제어할 수 있습니다.
'Laravel > Livewire' 카테고리의 다른 글
| Livewire 이벤트 수신시 매개변수($payload) 전달방법에 대해서 (0) | 2025.12.28 |
|---|---|
| Livewire 이벤트 송신 및 수신 (0) | 2025.12.21 |
| Livewire.dispatch 데이타 전달하기 (0) | 2025.10.12 |
| Livewire3와 Alpinejs 상호작용에 대해서. (0) | 2023.12.14 |