React-router: External javascript files stop working after first page change

Created on 6 Apr 2016  路  9Comments  路  Source: ReactTraining/react-router

I am using react in conjunction with react-router and webpack to bundle it all.
My problem is that I am also bound to using 3 external javascript files as plugins in my project.
Whenever I change pages with react-router, through the Link component, these javascript files seem to stop working after the first page change. It doesn't matter how I import the files.. Using either the script-loader with an import statement or just putting the tags in the base html file itself.
One of these plugins is jquery. The other two are just custom javascript plugins.

Most helpful comment

You are probably attaching to DOM nodes that get removed when the route changes.

However, this is a bug tracker. For support, please use Stack Overflow or Reactiflux. Thanks!

All 9 comments

You are probably attaching to DOM nodes that get removed when the route changes.

However, this is a bug tracker. For support, please use Stack Overflow or Reactiflux. Thanks!

Will do.. But I am not doing so. I am attaching the scripts to the outermost parent component from which the routes branch.

I do not mean the script elements, I mean the event listeners being attached by your jQuery and other scripts. They need to be told to reattach listeners when the route changes.

I see. Very obvious mistake. Thanks for the heads up.

By the way.
In the end all I had to do in each component which represented a new page was to add the following.

componentWillMount() {
    loadjs('/static/js/jquery.min.js', function() {
      loadjs('/static/js/plugins.js', function() {
        loadjs('/static/js/scripts.js');
      });
    });
  }

Being mindful that this will generate network requests for these files each and every time the user navigates to one of these components, but also that this issue is easily taken care of if you take into account browser caching.
loadJS works just like scriptjs in that if you want to load stuff synchronously all you have to do is write your statements in this nested callback pattern.

Note: If you add triple backticks (```) around your code you get a fenced code block, which makes the code a lot easier to read. I've edited your comment, would appreciate you doing that next time!

Hey @luishdosreis

My guess is you've got some scripts in scripts.js that, when loaded, immediately run some selectors on elements on the page and "dress them up" with jQuery, like $('.someStuff').makeItAwesome(). When you transition with React Router, the page doesn't reload, so your code doesn't automatically run again, you're going to need to wrap up your behaviors into a function and call it on route changes, and then you can call that function onUpdate of the router:

<Router onUpdate={runJQueryScripts}/>

And then that will go select the elements and do the jQuery things to them.

To verify if this is the problem, only reload scripts.js, but not jQuery.js and plugins.js

Hello @ryanflorence ,

Thanks for your help by the way.
Indeed, curiously enough, if I do remove the jquery.min.js and plugins.js load statements from every page but the home index, and load scripts.js on all of the pages, it all works fine.
If I then remove scripts the interactions break.
But that would mean, with my current solution, that the user would have to enter the app through the home route every single time, which isn't really the case.
In scripts.js there are 3 functions which initialize the jQuery code. However I have tried the approach above without success

function loadJquery() {
  $(window).load(function() {
      "use strict";
      $(".loader").fadeOut(500, function() {
          $("#main").animate({
              opacity: "1"
          },function(){contanimshow();});
      });
  });
  $(document).ready(function() {
      initMonolit();
      initparallax();
  });
}
export default ( <Route onUpdate={() => loadJquery()} path="/" component={App}> 
...

I don't know if what I have written for the onUpdate callback is correct though. As in, theoretically it should load it all but it doesnt.

Now if I add this:

  componentWillMount() {
    loadjs('/static/js/plugins.js');
    loadjs('/static/js/scripts.js', function() {
      $(window).load(function() {
          "use strict";
          $(".loader").fadeOut(500, function() {
              $("#main").animate({
                  opacity: "1"
              },function(){contanimshow();});
          });
      });
      $(document).ready(function() {
          initMonolit();
          initparallax();
      });
    })
  }

to every single route (component), and then just load jquery.min.js on the parent app component (the layout component where all the other routes are rendered) it all works again. It's good to point out that now the user won't have to enter through home for the website to work.

I have spent 3 full days to figure out this issue in my project, after 3 days I reached here and read this issue.
And calling loadjs() inside the compoentWillMount() actually worked.

This feature of loading external JS files should be by default in React router v4.
As every application that is using React router needs the JS files loaded for every route.

I am happy at least there is a solution to this issue. :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wzup picture wzup  路  3Comments

yormi picture yormi  路  3Comments

davetgreen picture davetgreen  路  3Comments

misterwilliam picture misterwilliam  路  3Comments

nicolashery picture nicolashery  路  3Comments