Laravel Livewire Javascript data is not refreshed after component is re-rendered

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

The Livewire Synchronization Challenge: Why JavaScript Data Fails to Refresh on Component Re-render

As developers working with modern full-stack frameworks like Laravel and Livewire, managing the synchronization between server-side state (PHP) and client-side interactivity (JavaScript) is often the trickiest part. We frequently encounter scenarios where component re-renders occur, data updates correctly on the server, but the connected front-end JavaScript fails to pick up those changes, leading to stale data in interactive libraries like FullCalendar.

This post dives deep into why your JavaScript data isn't refreshing when a Livewire component is re-rendered, specifically focusing on integrating dynamic data with external JavaScript libraries. We will analyze the provided scenario and establish the correct pattern for ensuring seamless synchronization.

Understanding the Disconnect: Livewire, DOM, and Client-Side State

The issue you are facing—where $events updates in your PHP code (visible via dump()) but the JavaScript data remains static—stems from how Livewire manages DOM updates versus how client-side scripts initialize themselves.

When a Livewire component re-renders:

  1. Server Side: The PHP/Blade logic runs, and the $events variable is correctly updated with the new data.
  2. DOM Update: Livewire sends only the necessary HTML changes to the browser.
  3. JavaScript Execution: If your JavaScript initialization code was set up once (e.g., on page load or a single contentChanged event), it does not inherently know that the underlying data source has changed unless explicitly told to re-read and re-process the new state.

In your specific case with FullCalendar, you are initializing the calendar object based on an initial snapshot of $events. When the component refreshes, the JS script is likely executing its setup logic against the stale data it captured initially, or it misses the signal to refresh the underlying library instance.

The Solution: Explicit Re-initialization and Event Handling

The key to fixing this lies in moving from passive listening to active instruction. Instead of just sending raw data, you must ensure your JavaScript logic explicitly re-processes the new data whenever a change is signaled from the server. This pattern keeps your front-end synchronized with the Livewire state, adhering to the principles of robust component architecture championed by frameworks like Laravel.

Refining the Integration Pattern

Your current approach using dispatchBrowserEvent('contentChanged') is correct for signaling changes, but the handling within the JavaScript needs refinement. We need to ensure that when this event fires, the script doesn't just log the old data; it re-reads the full dataset and forces the FullCalendar instance to refresh its events.

Here is how we can refine your implementation:

1. Server-Side Data Preparation (Blade)

Ensure you are passing the complete dataset whenever a change occurs, which you are already doing with @js($events). The focus shifts to making the JavaScript consumer smarter about this incoming data.

2. Client-Side Synchronization (JavaScript)

We need to ensure that when contentChanged fires, we don't rely solely on the initial @js() value but trigger a full re-initialization or refresh of the calendar instance using the freshest data.

document.addEventListener('contentChanged', function() {
    console.log("Livewire content changed. Re-initializing FullCalendar.");
    
    var Calendar = FullCalendar.Calendar;
    var calendarEl = document.getElementById('calendar');
    
    // 1. Read the latest data passed from Livewire
    const latestEventsData = @js($events); // Read the updated data here

    var calendar = new FullCalendar.Calendar(calendarEl, {
        locale: "de",
        // Note: We use the fresh data object for mapping events
        events: JSON.parse(latestEventsData).map((event) => ({
            ...event,
            backgroundColor: event.title < 3 ? '#B23220' : (event.title < 11 ? '#C3B031' : '#20B22C'),
            borderColor: event.title < 3 ? '#B23220' : (event.title < 11 ? '#C3B031' : '#20B22C'),
        })),
        headerToolbar: {
            left: 'prev,next today',
            center: 'title',
            right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
        },
        loading: function(isLoading) {
            if (!isLoading) {
                this.getEvents().forEach(function(e){
                    if (e.source === null) {
                        e.remove();
                    }
                });
            }
        },
    });

    calendar.render();

    // 2. Crucially, ensure the refresh mechanism is called on every update
    @this.on(`refreshCalendar`, () => {
        if (calendar) {
            calendar.refetchEvents();
        }
    });
});

Best Practices for Livewire/JS Interoperability

To maintain clean separation and improve maintainability, consider using Livewire's built-in event mechanisms more directly rather than relying solely on global DOM events for complex data synchronization.

  1. Use Public Properties: Ensure all dynamic data you need in JavaScript is exposed as public properties within your Livewire component class.
  2. Delegate Actions: Instead of embedding complex initialization logic directly into the Blade file, create a dedicated JavaScript function that handles the FullCalendar setup and expose it via the @js() directive. This makes the JS cleaner and easier to test.
  3. Leverage State Management: For very complex applications, consider using Livewire's component state management or reactive properties to trigger specific JavaScript updates only when necessary, rather than forcing a full re-render of the entire script block on every single data change.

Conclusion

The failure to refresh your JavaScript data after a Livewire re-render is rarely an error in the server logic; it’s usually a communication gap between the server state and the client-side initialization routine. By shifting your focus from merely passing data to actively re-processing that data upon receiving a synchronization signal, you establish a robust pattern.

By explicitly re-reading the updated $events whenever the contentChanged event fires, and ensuring that external library methods like calendar.refetchEvents() are called within those listeners, you guarantee that your front-end remains perfectly synchronized with the Laravel backend. Keep leveraging the power of Livewire to build dynamic applications, focusing on this synchronization layer for truly seamless user experiences. For more guidance on building scalable applications with Laravel, explore resources on the official Laravel documentation.