Skip to content

useEchoNotification callback not invoked in React StrictMode #482

@giuseppe-osenda

Description

@giuseppe-osenda

Echo Version

2.3.0

Laravel Version

12.53.0

PHP Version

8.5

NPM Version

11.10.0

Database Driver & Version

No response

Description

I couldn't explain why useEchoNotification callback didn't get called so i asked AI and this is what has found after digging through the file node_modules/@laravel/echo-react/dist/index.js:

### AI Output
useEchoNotification silently fails to bind its notification listener when the app is wrapped in <React.StrictMode>. The channel subscription succeeds and events arrive (visible in the network tab), but the callback is never invoked.

useEcho works correctly under the same conditions.

Root cause

In useEchoNotification, the listen function (h) uses a hasSubscribed ref (g) to guard against duplicate .notification() calls:

const h = u(() => { c.current || (g.current || r.channel().notification(b), c.current = !0, g.current = !0); }, [b, r]);

The cleanup function resets c (isListening) but not g (hasSubscribed):
const a = u(() => { c.current && (r.channel().stopListeningForNotification(b), c.current = !1); }, [b, r]);

In StrictMode, React runs effects, cleans them up, and re-runs them. During cleanup, stopListeningForNotification(b) unbinds the handler and c is reset to false. Meanwhile, useEcho (internally) leaves and re-creates the channel. On the second mount, h() is called again but g.current is still true (refs persist across StrictMode remounts), so r.channel().notification(b) is skipped. The new channel has no notification listener bound.

By contrast, useEcho handles this correctly because its useEffect unconditionally re-binds listeners via o() on every mount cycle.

### END AI OUTPUT

The workaround is to use useEcho directly with the notification event name:

useEcho( channelName, '.Illuminate\\Notifications\\Events\\BroadcastNotificationCreated', (notification) => { if (notification.type === 'your_notification_type') { // handle notification } }, );

Steps To Reproduce

  1. Wrap your app in <React.StrictMode> (default for create-react-app / Vite React templates)
  2. Use useEchoNotification to listen for notifications on a private channel
  3. Broadcast a notification to that channel
  4. Observe: channel subscription succeeds, event arrives in the WebSocket, but the callback is never called

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions