[Solved] Functions stop working after route change

I have a strange problem, I’ll try to put it in simple terms(edit: explain with an example). I’m using React + React Router(v4) with meteor.

In page2, I have imported a js file (import ‘./…/…/js/Utils.js’)

//Utils.js
$( "#myDiv" ).hover(
  function() {
    $( this ).addClass( "hover" );
  }, function() {
    $( this ).removeClass( "hover" );
  }
);

If /page2 is loaded directly everything works as expected but when navigated to /page2 from /page1 the code in Utils.js is not executed and no errors are shown!

//Routes.js
      <BrowserRouter>
        <Switch>
          <Route path="/page1" exact component={Page1} />
          <Route path="/page2" exact component={Page2} />
        </Switch>
      </BrowserRouter>

So for now, I figured out a small hack. By using forceReferesh={true} in BrowserRouter everything is working as expected. But I don’t to want reload the page for every new route.

Okay to summarize, if I include external js file on client/main.html and navigate to different routes, the functions inside that js file aren’t getting called. They are working fine, if I use forceRefresh={true} on BrowserRouter. Any help is appreciated, TIA.

P.S:
I found someone with similar problem (if not exact situation) here: External javascript files stop working after first page change · Issue #3256 · remix-run/react-router · GitHub

Imported code is not run every time it is imported, It will only run once.

The recommended pattern for js in general is to export a function that does what you want and then call that function when you need to.

I feel as though there’s a much better way to do this in React than using jQuery like this. I’ll let a React user give a better answer.

The Blaze equivalent of how to do this is on the template’s event-map

Template.Page2.events({
  'mouseenter'(event) { 
    event.target.classList.add('hover'); 
  },
  'mouseleave'(event) { 
    event.target.classList.remove('hover') 
  },
});

The key thing to note being that the handlers are bound to the template, so they are added when the template is rendered and removed when it is destroyed. That way when your router renders a new page, and all the elements within it, the handlers are attached.

thanks for your answer. The function is just an example function ( i edited my post to make it more clear, my bad).
The bigger problem is this: if I include external js file on main.html and navigate to different routes, the functions inside that js file aren’t getting called but works with the hack I mentioned.

Which file?
Is it a UMD module?
Does it have an API that you can call?

Generally speaking JQuery and React don’t play nice together, especially in cases where you’re directly modifying the DOM. You’ll want to use React’s synthetic events instead of JQuery’s events.

class Whatever extends React.Component {
    state = { hoverClass: "" }
    render() {
        return (
            <div 
                onMouseEnter={() => this.setState({hoverClass:"hover"})}
                onMouseLeave={() => this.setState({hoverClass:""})}
                className={this.state.hoverClass}
            >
                Content!
            </div>
        )
    }
}
2 Likes

@coagmano @copleykj guys…I can modify the code to react but I’m looking for the reason cause the same code is working if forceRefresh={true} on BrowserRouter is added.

Why the statement import '././..././js/somefile.js or inline script tag doesn’t make the functions work incase of routing but works upon refresh?

P.S: The js files on point are plugins/scripts file from a theme.

Okay finally, I fixed it.

Including solution for future references:

  1. Put your js/jquery code in in a static function of react class.
  2. Call the function in componentDidLoad method of the component you want to manipulate.

Thanks all for your time :slight_smile:

1 Like