Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route change event #964

Closed
bkniffler opened this issue Mar 17, 2015 · 33 comments
Closed

Route change event #964

bkniffler opened this issue Mar 17, 2015 · 33 comments

Comments

@bkniffler
Copy link

Hey,
I need to add a route change event handler within my route definition.

AuthModule/Routes.js

Router.createRoute({ path: /login, name: "auth-login", handler: App, parentRoute: route }, function(){
        Router.createDefaultRoute({ handler: Login });
        Router.createRoute({ path: "/register", name: "auth-register", handler: Register });
    });

// This is what I need
Router.on("transition", function(from, to, cancel){
// e.g. if !loggedIn && to.name.indexOf("auth-") != 0 -> cancel
})

Using statics on handlers is not a solution (avoid boilerplate), also using Router.Run to track route changes isn't my preferred solution (not modular). Is there anything available like this?

Thanks in advance!

@bkniffler
Copy link
Author

Thanks for your help, though I knew of this solution. I really prefer to let my router decide what location needs authentication instead of the component. As I use the programmatic API, this solution suits my needs:

var transitionHandler = function(transition) {
       // could also check transition.path
            if (!AuthStore.isAuthenticated()) {
                transition.redirect('login', {}, {nextPath: transition.path});
            }
        }

Router.createRoute({ name: "route1" , onEnter: transitionHandler });
Router.createRoute({ name: "route2" , onEnter: transitionHandler });

@calbertts
Copy link

Hi,

There is way to use "onEnter" with JSX?

@tristanbbq
Copy link

+1 looking for answers on previous question from @calbertts

@robert-chiniquy
Copy link

This example: https://github.com/rackt/react-router/blob/master/examples/auth-flow/app.js#L129 suggests to me that you can. I'm not having luck making it work though, so I have the same question as @calbertts.

@mcobzarenco
Copy link

+1

I have the same question as @calbertts (I couldn't get the example at https://github.com/rackt/react-router/blob/master/examples/auth-flow/app.js#L129 to work)

@mrondon
Copy link

mrondon commented Aug 2, 2015

+1 same here
(I couldn't get the example at https://github.com/rackt/react-router/blob/master/examples/auth-flow/app.js#L129 to work)

@bkniffler bkniffler reopened this Aug 2, 2015
@itaibaruch
Copy link

I manage to make the auth example work by adding "super()," in the constructors.

class App extends React.Component {
constructor () {
super(),
this.state = {
loggedIn: auth.loggedIn()
};
} ......

@gobwas
Copy link

gobwas commented Sep 2, 2015

What about this issue now?

@ryanflorence
Copy link
Member

master (forthcoming 1.0 API) has hooks on routes, check out the auth example and the docs

@mcobzarenco
Copy link

@ryanflorence Not sure you read the discussion above, this issue concerns the onEnter callback added in version 1.0

@martpie
Copy link

martpie commented Sep 15, 2015

Same question as @mcobzarenco

As the doc seems to be for 1.0 and a lot of us still uses 0.13.3, a lot of examples do not work. onEnter and onLeave on <Route> do not trigger anything.

@heyheyjp
Copy link

If you're using 0.13.x, you'll want to be sure to reference the 0.13.x docs. I think we've got a broken link from the 0.13.x branch README that unfortunately sends you to docs for 1.0.x. We'll fix that.

In the meantime, you can find docs for 0.13 here: https://github.com/rackt/react-router/tree/0.13.x/doc

@hiddentao
Copy link

For detecting route change within a component (e.g. if just the URL parameter changes) I've managed to get change detection working with a mixin:

module.exports = {
  componentWillMount: function() {
    this.setState({
      _routePath: this.getPath(),
    });
  },

  componentWillUpdate: function() {
    var newPath = this.getPath();

    if (this.state._routePath !== newPath) {
      this.setState({
        _routePath: newPath,
      });

      if (this.onRouteChanged) {
        this.onRouteChanged();
      }
    }
  },
};

Then in your component simply add a onRouteChanged method to handle the route change.

@frg
Copy link

frg commented Sep 24, 2015

@hiddentao Do you have any idea why this is being triggered twice every route change?

Edit: You should use "componentWillReceiveProps" instead of "componentWillUpdate"

@hiddentao
Copy link

@frg Thanks for that. If onRouteChanged is being called twice then my guess is that the setState() call isn't being processed in time (thus causing this.state._routePath to still be the old path) before the second time the lifecycle method gets invoked - thus causing onRouteChanged to be called again.

@andrx
Copy link

andrx commented Oct 1, 2015

I do it like this, ataching event to Location:

componentDidMount() {
    this.context.router.getLocation().addChangeListener(listener);
}
componentWillUnmount() {
    this.context.router.getLocation().removeChangeListener(listener);
}

using Router.HistoryLocation

Router.run(routes, Router.HistoryLocation, (Handler, state) => { ... });

@321ckatz123
Copy link

Since a few people above have asked about onEnter in jsx and I didn't see an answer, this appears to work just fine to me:

function temp() {
  console.log('Hi');
}

const routes = (
    <Route path='/' component={Index}>
      <Route path='path1' component={comp1} onEnter={temp} />
      <Route path='path2' component={comp2} onEnter={temp} />
      <Route path='*' component={FourZeroFour}/>
    </Route>);

@shea256
Copy link

shea256 commented Jan 25, 2016

@andrx your solution is great. Saved me a bunch of trouble.

There was a problem with your code, though, so I made a few modifications and ended up with this:

componentDidMount() {
  this.context.router.listen(this.locationHasChanged)
}

componentWillUnmount() {
  this.context.router.unregisterTransitionHook(this.locationHasChanged)
}

Works beautifully.

@robert-chiniquy
Copy link

Yeah onEnter is fine now since react-router 1.0.

@sekoyo
Copy link

sekoyo commented Jan 27, 2016

Is there a way to listen to all route changes? For some reason my windows popstate event isn't being fired (perhaps it's being consumed by react-router?) and onChange/onUpdate doesn't seem to work on the top level route? Thanks

@martpie
Copy link

martpie commented Jan 27, 2016

@dominictobias You can call the same function for all routes and use a callback to distinguish each route if you need a custom behavior.

@sekoyo
Copy link

sekoyo commented Jan 27, 2016

Thanks for the fast reply @KeitIG, I'm not sure if this is supposed to be internal but I discovered a more convenient approach:

browserHistory.listen(function(ev) {
  console.log('listen', ev.pathname);
});

<Router history={browserHistory}>{routes}</Router>

@martpie
Copy link

martpie commented Jan 27, 2016

Looks better indeed :)

@taion
Copy link
Contributor

taion commented Jan 27, 2016

Please open a question on Stack Overflow and we'll answer it there.

@russormes
Copy link

@dominictobias Thanks for that, I went with your solution. With a large number of routes it is not practical to add the callback to each one and also the onEnter function could get quite busy if you want to use it for authentication, authorisation etc.

@puranjayjain
Copy link

puranjayjain commented May 24, 2016

If someone is still troubled with this issue I am using a custom solution with Eventemitter.
See the files here
The relevant files are:

  • subviews/Addurl.js
  • helpers/mrEmitter.js
  • app/Sidebar.js
  • app/Main.js

If you are looking for a small example see this

@DullReferenceException
Copy link

Any reason why browserHistory.listen is not documented?

@hugodutra-zz
Copy link

@dominictobias I've spent all my day trying to find a way do handle route changes. THANKS A LOT!

@mrdulin
Copy link

mrdulin commented Sep 1, 2016

I test and give you this:

console.log('this.context.router is same as this.props.router', this.context.router === this.props.router); //true
console.log('this.context.router is same as browserHistory', this.context.router === browserHistory);   //false
console.log('this.context.router.push is same as browserHistory.push', this.context.router.push === browserHistory.push);   //true

@phun-ky
Copy link

phun-ky commented Sep 16, 2016

Tried to find a method for this as well and ended up here, but I just realized I already have it:

<Router history={browserHistory} onUpdate={this.doStuffOnUpdate}>....</Router>

Maybe I'm interpreting it wrong, but this seems to work fine for me, ref: https://github.com/ReactTraining/react-router/blob/master/docs/API.md#onupdate

@Meesam
Copy link

Meesam commented Feb 28, 2017

try to implement HOC (Higher order component), you can take reference below code

import React,{Component,PropTypes} from 'react';
import {connect} from 'react-redux';

export default function (ComposedComponent) {
  class Authentication extends Component{
    static contextTypes={
      router:React.PropTypes.object
    }

    componentWillMount(){
     console.log(this.props.authenticatedUser);
      let token = localStorage.getItem('jwtToken');
      if(this.props.authenticatedUser==='logout' || token==='undefined'){
        this.context.router.push('/login');
      }
    }

    componentWillUpdate(nextProps){
      console.log( 'tt ' +nextProps.authenticatedUser);
      let token = localStorage.getItem('jwtToken');
      if(nextProps.authenticatedUser==='logout' || token==='undefined'){
        this.context.router.push('/login');
      }
    }

    render(){
      return(<ComposedComponent {...this.props} />)
    }
  }

  function mapStateToProps(state) {
    return {
      authenticatedUser: state.user.status,
      user: state.user
    };
  }
  return connect(mapStateToProps)(Authentication) ;
}

@rahul-sr
Copy link

I need to do something before the route change. Is there any before route change event?
browserHistory.listen handler is fired just immediately after route changes.

@ivmarcos
Copy link

@vnsrahul1304, try browserHistory.listenBefore

@remix-run remix-run deleted a comment from jsphstls Oct 26, 2017
@lock lock bot locked as resolved and limited conversation to collaborators Jan 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests