stimulusreflex / stimulus_reflex

Build reactive applications with the Rails tooling you already know and love.
https://docs.stimulusreflex.com
MIT License
2.28k stars 172 forks source link

stimulus_reflex.js:388 Uncaught TypeError: Cannot read property 'completedOperations' of undefined #394

Closed davissp14 closed 3 years ago

davissp14 commented 3 years ago

Bug Report

Issue that just seemed to crop up after upgrading Ruby + Stimulus Reflex.

I am using the content_reloader via the tutorial here. The only difference is that instead of using fetch to apply new changes, I am using this.stimulate to re-render the content. https://stimulusjs.org/handbook/working-with-external-resources

When navigating away from the page that contains this controller, I start receiving these error messages. In fact, I keep getting automatically redirected to the page containing this controller. I'm guessing that Reflex is holding onto the operations despite me navigating away. When the operation triggers it directs me back to the original view.

The frustrating bit, is that I can't reproduce this locally. Only in production.

Screen Shot 2020-11-30 at 1 48 37 PM

Any ideas what could be going on here?

Versions

StimulusReflex

External tools

Browser

davissp14 commented 3 years ago
import { Controller } from 'stimulus'
import StimulusReflex from 'stimulus_reflex'

export default class extends Controller {

  connect() {
    StimulusReflex.register(this)
    if (this.data.has("refreshInterval")) {
      this.startRefreshing()
    }
  }

  disconnect(){
    console.log("disconnecting")
    this.stopRefreshing();
  }

  load() {
    console.log('stimulating')
    this.stimulate()
  }

  startRefreshing() {
    this.refreshTimer = setInterval(() => {
      this.load()
    }, this.data.get("refreshInterval"))
  }

  stopRefreshing(){
    if (this.refreshTimer) {
      console.log("Stopping refreshTimer")
      clearInterval(this.refreshTimer)
    }

  }

}
leastbad commented 3 years ago

Hi Shaun,

What version of StimulusReflex are you using? What version of Stimulus are you upgrading to? Are you using Turbolinks?

Can you please confirm that you've read and understood https://docs.stimulusreflex.com/troubleshooting#dont-initiate-a-reflex-when-your-page-has-finished-loading as it seems like you're attempting to stimulate() when you load the page. This isn't how StimulusReflex is intended to be used.

A little bit of context for what you're trying to do in layman's terms would be a big help.

Finally, this would go much faster if you could prepare a quick MVCE showing the behaviour that you're seeing. An easy way to do this is to clone https://github.com/leastbad/stimulus_reflex_harness and post your own branch so we can run it locally.

Thanks!

davissp14 commented 3 years ago

Update:

I downgrade to Ruby 2.6.3 and Stimulus Reflex 3.2.3 and the problem was resolved. I'll review your comment further to see if I can provide additional context, here.

davissp14 commented 3 years ago

What version of StimulusReflex are you using?

I've tried both 3.2.3 and 3.3.0

What version of Stimulus are you upgrading to

Haven't updated this, nor tried. Stimulus/core is locked at ^1.1.1

Are you using Turbolinks

Yes

Can you please confirm that you've read and understood https://docs.stimulusreflex.com/troubleshooting#dont-initiate-a-reflex-when-your-page-has-finished-loading as it seems like you're attempting to stimulate() when you load the page. This isn't how StimulusReflex is intended to be used.

Right, this doesn't initiate a morph on page load. On connect() I configure an interval in which to trigger stimulate. In my case, it will call stimulate() every 60 seconds ( starting 60 seconds after the initial connect()).

A little bit of context for what you're trying to do in layman's terms would be a big help.

I have a dashboard with buttons that are only enabled at specific times. I have a stimulus controller that sets up to reload the page every 60 seconds, reference: https://github.com/hopsoft/stimulus_reflex/issues/394#issuecomment-736019402

Note: I still haven't been able to reproduce this specific issue locally.

leastbad commented 3 years ago

I only asked about Stimulus because your issue started by saying that you'd upgraded it.

If moving to 3.2.3 solves the problem you're having, that's great - but we're on the verge of releasing 3.4 and we follow SemVer but each minor release brings a huge amount of new functionality. The version you should be testing against today, IMO, is 3.4.0.pre6, not 3.2.3. YMMV!

I just re-read your issue... are you saying that you can navigate to an entirely different page (on another domain) and this will keep happening? Or is it confined to just your app?

My sense is that since your page context isn't being refreshed (Turbolinks) the setTimeout is still going to happen because it doesn't know what Turbolinks is (or care). This means that you need to capture the turbolinks:before-cache DOM event (which is the only one that runs before navigation, back and cached):

// first visit: load
// click: click before-visit request-start visit request-end before-cache before-render render load
// back: visit before-cache before-render render load
// cached: click before-visit request-start visit before-cache before-render render request-end before-render render load

In the handler for turbolinks:before-cache you can clearInterval(this.refreshTimer) and the problem should go away.

zhongsheng commented 3 years ago

If import "controllers" more than once will produce this problem. And ensure to use nodejs12, with nodejs10 afterReflex callback not work.

leastbad commented 3 years ago

Hi @zhongsheng!

@davissp14 says that it's working in development but not in production. Unless he's not testing in development before deploying, hopefully he's caught any duplicate import "controllers" mishaps.

I'm honestly not sure what you mean about nodejs 10 vs 12. Could you go into more detail? It's the first time I'm hearing about this, given that it is a client library.

fedegl commented 3 years ago

I've seen the error as well in both development and production.

In development, I have been able to reproduce it by opening the same URL in 2 different browser windows and then executing a reflex. The error happens on the window where the action wasn't triggered.

I haven't been able to reproduce the same scenario on production myself, but I have seen errors on Honeybadger from other users.

fedegl commented 3 years ago

I realized that I also had imported controllers twice, but even after fixing that, I still see the issue happening.

fedegl commented 3 years ago

I am on Ruby 2.7.2 and Stimulus Reflex version 3.3.0 for both gem and npm package.

leastbad commented 3 years ago

I strongly advise that you upgrade to v3.4.0.pre8 (and soon, pre9) as this is unfortunately a known issue in v3.3 that cannot be easily fixed.

davissp14 commented 3 years ago

Upgrading to 3.4.0.pre8 did seen to resolve the issue. Appreciate it!

leastbad commented 3 years ago

Awesome! pre9 will be out soon, and it's non-trivially improved from pre8 in subtle but important ways. Keep your eyes peeled. 😀

fedegl commented 3 years ago

It did resolve it for me as well. Thanks! 💯