Detect the current route in a view

I have a header bar. I would like to enable some controls if a user is in a particular route. For example, if a user is viewing a dashboard page, I want to enable a Create button on the header bar. It looks like react-router utilities are not available in redwoodjs. I end up doing some pathname matching. It’s not ideal.

Is there a way to detect the current route in a view? Maybe routes object can return current() with the route’s name and params (e.g. id). So when a user is viewing “/dashboards/1234”, routes.current() will return {name: “viewDashboard”, id: "1234}.

Hi @dnprock! Have you tried the Router useParams() hook? That might do the trick.

Also, if I understand your use-case correctly (e.g. enable components or states based on use being logged-in), you might be able to use isAuthenticated() for the logic. (Thoughts about this approach, @peterp?)

1 Like

@thedavid
I want to show one model pop-up based on a route param regardless of the page I am on currently!
For this my flow is something like,

  • There is a button that will add a param in current route (as query string ?show=true)
    i.e.

     navigate(routes[*currentRouteName*]({...currentParams, show: true}))
    
    
  • In Layout render I have something like currentParams.show && <Popup />

  • Close button inside that pop up will remove that param.
    i.e.

      delete currentParams.show
      navigate(routes[*currentRouteName*](currentParams)) 
    
    

Is there any way to add/remove params in current route or any way I can get current route name?

Hi @mahesh-beehively .

Have you tried the useLocation hook as documented in Redwood Router?

If you’d like to get access to the current URL, useLocation returns a read-only location object representing it. The location object has three properties, pathname, search, and hash, that update when the URL changes.

https://redwoodjs.com/docs/redwood-router#uselocation

const { pathname, search, hash } = useLocation()

@dthyresson
yes I have checked useLocation but that doesn’t seems much useful here as I want to stay on current route with current params, by just adding or removing one specific param from that.

    navigate(routes[*currentRouteName*]({...currentParams, show:true})) 

does exactly what I need. Only missing part is currentRouteName

Unless I am misunderstanding, navigate takes a string – the path.

I’m ask to see if there is a better way – or definitely welcome a PR to create one – but

You could recreate the navigate(to) where the to is ${pathname}{search}&show=true or use some utils to create the querystring better from those parts returned from useQuery … and useParams can fetch the current params.

Might there be a more React event way (ie useState) to invoke the modal? And then in the page you could always check for the param if coming in from an external referrer with show = true.

1 Like

@dthyresson
Yes, invoking modal is done in react way and that part works fine.
Currently I am constructing the URL manually as you’ve describe, it’s just that it doesn’t feel like redwood way and thought to ask here if there is any way to get currentRouteName.

1 Like

Often there isn’t a “RedwoodJS” way – yet – but if you find or implement a solution, can be “the way”.

But, I think it’s different question to ask how Redwood might invoke a modal from a UI component vs how React might do the same. It could be the same method to invoke – but just a different mechanism to know how or when to invoke. That’s why I posed:

But - if there was a way to get the current route from useLocation() would that solve your problem?

If so, then I’d suggest creating an issue and to describe the use case – why the pathname that is currently provided isn’t sufficient.

It might be that instead navigate or something else could be enhanced to create a route/to from a string or path and build that querystring.

Fundamentally, you want to know how to invoke a modal dialog – right? If it involves the current route or path or some params, that is a method but maybe not the one.

It still strikes me that using React state to do something like:

const [showModal, setShowModel] = useState(false);

And then render the dialog when showModal is true and have a button (or look at the page’s params) to setShowModal = true.

I tried useLocation and it complained that it was not within a LocationProvider

I wrapped one of those around the App just inside the RedwoodApolloProvider and routing stopped working

I imagine there is one of the already wrapping something for me

I need to do things in the AppBar, outside the Routes Element…

Guessing since the docs do not mention a LocationProvider…

@ajoslin103 You are correct, the <Router> element already has the <LocationProvider> added for you. So if you need your <AppBar> to be aware of the location you’ll have to move it inside the router. Like maybe put it in a top level Layout. Would that work for you?

@Tobbe

I could not move the AppBar into the Router

So I wrapped the contents of the AppBar in a LocationProvider – then all functioned as it should.

            <AppBar position="static">
              <LocationProvider>
                <Toolbar>
                  <NavMenu />
                  <Box className={classes.flexGrow}>
                    <Typography variant="h5" className={classes.appBarTitle} onClick={clickHome}>
                      {AppBarTitle}
                    </Typography>
                  </Box>
                  <AvatarMenu />
                  <LogInOutButton logOutOptions={{}} />
                </Toolbar>
              </LocationProvider>
            </AppBar>

I could then call the useLocation() hook as needed anywhere inside the LocationRouter

export const AvatarMenu: React.FunctionComponent = () => {
  const { pathname } = useLocation()
  const { isAuthenticated } = useAuth()
  const hideAvatarMenu = shouldHideAvatarMenu(isAuthenticated, pathname)
  [etc, etc, ...]

I was #FightingTheFramework and had to #RelaxIntoTheFramework

Redwood is sooooo good !

That’s an approach I wouldn’t have thought of. Thanks for sharing!

1 Like

I’m also trying to find a way of getting the name of the current route, so I can use it in this hook in my top level App component in order to make calls to segment’s analytics.page generically rather than having to do it on each individual page.

function usePageAnalytics() {
  const analytics = useAnalytics()
  const location = useLocation()
  // this would be the same as the `name` key in Routes.tsx
  const routeName = useRouteName() 

  useEffect(() => {
    analytics.page({name: routeName, properties: { ...location }})
  }, [location])
}

^^ @Tobbe any suggestions here?

Might you not want to use the meta head tags for page title instead?

You can also get the path from useLocation().

@thedavid Thanks for the ping

There currently isn’t a way to get the name of the active route. But I can definitely see the value. I think it would be a fairly small and simple thing to add to the router. Except for the types. We’d want to somehow use the types we generate for the router. But I don’t know off the top of my head how I’d go about making that all work.

@stephenhandley Would you mind creating a issue (more like a feature request) in our GitHub repo? Thanks! (If you don’t want to do it, just let me know and I’ll write it down.

2 Likes

Awesome thanks @Tobbe here’s the feature request issue

@dthyresson useLocation / path doesn’t really work for identifying a page due to the parameterization since multiple path values will identify the same page. Although I want that information in the analytics event, because of the parameterization it isn’t immediately useful without aggregating / having some route-aware logic in the analytics tier, which is what I’d like to avoid.

1 Like