livewire: initial-data attribute not found in component after updating to 1.0.1

I updated livewire from 0.7.4 to 1.0.1 and after updating I get this error in the console.

index.js:19 Uncaught TypeError: Cannot read property 'data' of null
    at new Component (index.js:19)
    at index.js:69
    at Array.forEach (<anonymous>)
    at Livewire.start (index.js:67)
    at HTMLDocument.<anonymous> (dashboard:38)

The attribute is in the rendered HTML but when the component is parsed by livewire, it is not found.

Update:-

I dug into the issue a little bit morning. Here are the steps to reproduce the issue. I assume that you have a fresh installation of Laravel with livewire and Turbolinks installed and configured.

  1. Create two separate livewire components.
  2. Include those two livewire components in two separate pages.
  3. Now add links into your layout to navigate between the two pages.
  4. Now navigate to any one of the pages and then quickly navigate to another page while the previous page request is still pending.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 12
  • Comments: 60 (8 by maintainers)

Most upvoted comments

Got the same error when using nested components and not using Turbolinks.

Fixed the issue by changing the nested component’s key to a random one.

Before

@foreach($contacts as $key => $contact)
    @livewire('child-component', [], key($contact->id))
@endforeach

After

@foreach($contacts as $key => $contact)
    @livewire('child-component', [], key(rand() * $contact->id))
@endforeach

And still don’t know why this tweak works 🤔

I just ran into the same issue with a simple list of posts, using a ‘post’ sub-component. Pagination will only work for the first click.

Seeing this too in my app.

Update: Found the problem. Disabling the options.views.data DataCollector in debugbar’s config resolves the issue for me. It appends multiple instances of the components’ rendered views to the DOM thus causing livewire to re-evaluate those, too. Eventually the Component constructor is run more than once.

Derived from that i guess that the problem boils down to a component with the same wire:id being in the DOM multiple times - regardless how it got there.


I get this error as soon as i add any component to a view, an “empty” one, too (v1.0.12). Logging console.log('initialize', this.id, initialData); in the Component constructor:

export default class Component {
    constructor(el, connection) {
        el.rawNode().__livewire = this
        this.id = el.getAttribute('id')
        const initialData = JSON.parse(this.extractLivewireAttribute('initial-data'))
        console.log('initialize', this.id, initialData);
        /*
        this.data = initialData.data || {}
        this.events = initialData.events || []
        this.children = initialData.children || {}
        this.checksum = initialData.checksum || ''
        this.name = initialData.name || ''
        this.errorBag = initialData.errorBag || {}
        this.redirectTo = initialData.redirectTo || false
        */
        // ...
    }
    // ...
    extractLivewireAttribute(name) {
        const value = this.el.getAttribute(name)
        this.el.removeAttribute(name)
        return value
    }
    // ...

With just one component on the page, it is constructed multiple times, deleting the initial-data attribute after the first time (present on initial load)

Screenshot 2020-04-22 at 14 33 22

Subsequent instantiations will cause said error as the attribute is not there anymore, obviously. Question is why the constructor is called that often ~, what removing the attribute was added for. Going by the commit date that error should’ve come up much earlier; something in the lifecycle of components changed recently?~

Not too deep into the code yet, just started using it yesterday. (Love livewire btw - such a treat to work with)

Agreed @indigoram89

It gets solved also by adding a key to every component. Not only to components rendered in loops. 👍

As this seems like a very common scenario, sub-component inside a foreach, this probably needs to be looked at.

I just ran into the same issue with a simple list of posts, using a ‘post’ sub-component. Pagination will only work for the first click.

Using the bulit-in Laravel pagination without the ‘WithPagination’ trait, it works fine as well.

Any ideas @calebporzio?

Having the same issue … not sure how to provide more detail. Here is what I’m seeing:

Screen Shot 2020-03-03 at 2 55 56 PM

I have encountered this this error when having a laravel component inside livewire component template that had a livewire component as a slot. Adding key didn’t solve it for me.

Just stumbled into this problem. Got it solved putting :keys to every nested component in a loop. Hopefully it helps!

I just ran into this, using nested components inside a foreach:

<livewire:list wire.poll>
    @foreach($items as $item)
        <livewire:item></livewire:item>
    @endforeach
</livewire:list>

The error appears when the list is updated from the wire.poll

Adding a unique key to the nested component did the trick for me:

<livewire:list wire.poll>
    @foreach($items as $item)
        <livewire:item :key="$item->id"></livewire:item>
    @endforeach
</livewire:list>

Adding the key attribute is not a big deal, although it is not a very obvious solution; maybe just adding a more verbose error message could help.

My issue (above) was resolved by adding https://github.com/livewire/vue. (I’ve updated my repository with the fixed version in this branch)

For my personal project I also needed to add window.vue = Vue in app.js as described here

Hello everyone! Want to share my two cents on how to fix these kind of bugs. I’ve had some eureka moments when working with Livewire. It’s not a vast list and it’s narrowed down to my experience with the framework.

  • Always put a key attribute when rendering components in a loop. Not :key or wire:key. Just key. This key must be unique among the rendered components.

image

  • Nested components by themselves do not need a key. However, they can break when rendering next to other dynamics parts of the view. For example

image

This will break the nested component when the foreach renders a new element. My wild guess is that Livewire tracks the position in the DOM where the component is located. Let’s say we have 10 items rendered, then our NestedComponent will be on the 11th position. When rendering 11 items, our component goes to the 12th position and it breaks. To avoid this, add a wrapper element to every dynamic sections of your view: foreach, if, etc.

image

This time, the Nested component will be always in the 2nd position, no matter how many the items the loop renders.

Hope this helps!

Ok I’ve also done some digging, this is with nested components inside of a @foreach:

<!-- resources/views/livewire/add-risk-areas.blade.php -->

@foreach($risk->areas as $area)
    @livewire('add-risk-area-button', ['risk' => $risk, 'area' => $area], key($area->id))
@endforeach

Once I removed the sub-component, I didn’t get this issue anymore…

Adding the key solves the problem for me:

@livewire(“path.to.component.{$model->id}”, [], key($model->id))

Okay, I’ve figured it out!

So, there are two noteworthy things here:

  • Given: “I updated livewire from 0.7.4 to 1.0.1” - Same here!
  • I am willing to bet that all of us have Turbolinks installed.

Previously, we needed to add this code to get Turbolinks and Livewire to work nicely together:

document.addEventListener('turbolinks:load', () => {
  if (!window.livewire) {
    window.livewire = new Livewire()
    window.livewire.start()
  } else {
    window.livewire.restart()
  }
})

Now, we don’t have to do that:

If you have Turbolinks installed on the page (installation instructions here), Livewire will handle the rest.

What was happening:

window.livewire.start() was being called in my code and in Livewire’s code. Calling this twice led to a bunch of code getting re-run twice, including this.extractLivewireAttribute('initial-data'). The attribute gets removed the first time start() is called, and fails the second time.

Boom!

First, I’ll say that sometimes when you see this error, it’s because you are loading @livewireScripts twice.

I added a console.warn to Livewire to help people with this case.

It appears there’s something deeper here with nested components.

I would love for someone to post an explicit replication of this error that I can copy and past requiring no domain code. Otherwise, it’ll be very hard for me to debug.

Thanks!

Well if you use

@foreach($contacts as $key => $contact)
    @livewire('child-component', [], key(rand()))
@endforeach

It will behave the same as:

@foreach($contacts as $key => $contact)
    @livewire('child-component')
@endforeach

Because livewire will add a random string as key if there is no key defined.

Any new about this problem. I don’t have a loop components, only nestes components, putting a fixed key is not solved problem.

Have you ever tried key(rand().'name...')?

Now work, with key(rand()) only not, very stranger…

Thank @heruputra

According to this document

Similar to VueJs, if you render a component inside a loop, Livewire has no way of keeping track of which one is which. To remedy this, livewire offers a special “key” syntax:

<div>
    @foreach ($users as $user)
        @livewire('user-profile', ['user' => $user], key($user->id))
    @endforeach
</div>

Got the same error when using nested components and not using Turbolinks.

Fixed the issue by changing the nested component’s key to a random one.

Before

@foreach($contacts as $key => $contact)
    @livewire('child-component', [], key($contact->id))
@endforeach

After

@foreach($contacts as $key => $contact)
    @livewire('child-component', [], key(rand() * $contact->id))
@endforeach

And still don’t know why this tweak works 🤔

After a long search, This one works for me.

Is there a temporary solution to this issue until it gets resolved?

Sorry, will need more info on the problem.