45

I'm using react-router v4 and material-ui in my React app. I was wondering how to change the URL once there is a click on a GridTile within GridList.

My initial idea was to use a handler for onTouchTap. However, the only way I can see to redirect is by using the components Redirect or Link. How could I change the URL without rendering those two components?

I've tried this.context.router.push('/foo') but it doesn't seem to work.

Alex
  • 831
  • 1
  • 9
  • 14

4 Answers4

81

Try this,

this.props.router.push('/foo')

warning works for versions prior to v4

and

this.props.history.push('/foo')

for v4 and above

Ayush Sharma
  • 1,747
  • 12
  • 22
  • @Alex The method are now passed as props intead of through context. But I am still having multiple issue with this stuff in production – CESCO Feb 16 '17 at 14:55
  • So this means I need to pass down to the child components the router object myself, right? – Alex Feb 17 '17 at 10:27
  • no, router will be there already, no need to pass – Ayush Sharma Feb 17 '17 at 11:23
  • I believe you must have to pass the props. e.g. ` }/>`. If I try to access props inside `MyComponent`, I don't believe that `props.router` will exist. `props` isn't a global variable and you can't just inject stuff into it. – icc97 May 27 '17 at 13:39
  • 3
    N.B. **This is for an old version of React Router** (current version is v4) – icc97 May 27 '17 at 21:58
  • If you're using a HOC you'll want to `import { withRouter } from 'react-router-dom` and wrap your component with it (i.e. `export default withRouter(MyComponent)`). This gives you access to the `history` prop. – Michael Lynch Dec 09 '19 at 15:33
  • You can make use of the [`useHistory`](https://reactrouter.com/web/api/Hooks/usehistory) thing. – x-yuri Apr 03 '21 at 15:10
42

I'm using this to redirect with React Router v4:

this.props.history.push('/foo');

Hope it work for you ;)

Jobsamuel
  • 1,280
  • 1
  • 13
  • 23
  • 1
    N.B. The subtle change from `router` to `history`. This is what I've used in the end to for v4 – icc97 May 27 '17 at 21:50
7

React Router v4

There's a couple of things that I needed to get this working smoothly.

The doc page on auth workflow has quite a lot of what is required.

However I had three issues

  1. Where does the props.history come from?
  2. How do I pass it through to my component which isn't directly inside the Route component
  3. What if I want other props?

I ended up using:

  1. option 2 from an answer on 'Programmatically navigate using react router' - i.e. to use <Route render> which gets you props.history which can then be passed down to the children.
  2. Use the render={routeProps => <MyComponent {...props} {routeProps} />} to combine other props from this answer on 'react-router - pass props to handler component'

N.B. With the render method you have to pass through the props from the Route component explicitly. You also want to use render and not component for performance reasons (component forces a reload every time).

const App = (props) => (
    <Route 
        path="/home" 
        render={routeProps => <MyComponent {...props} {...routeProps}>}
    />
)

const MyComponent = (props) => (
    /**
     * @link https://reacttraining.com/react-router/web/example/auth-workflow
     * N.B. I use `props.history` instead of `history`
     */
    <button onClick={() => {
        fakeAuth.signout(() => props.history.push('/foo'))
    }}>Sign out</button>
)

One of the confusing things I found is that in quite a few of the React Router v4 docs they use MyComponent = ({ match }) i.e. Object destructuring, which meant initially I didn't realise that Route passes down three props, match, location and history

I think some of the other answers here are assuming that everything is done via JavaScript classes.

Here's an example, plus if you don't need to pass any props through you can just use component

class App extends React.Component {
    render () {
        <Route 
            path="/home" 
            component={MyComponent}
        />
    }
}

class MyComponent extends React.Component {
    render () {
        /**
         * @link https://reacttraining.com/react-router/web/example/auth-workflow
         * N.B. I use `props.history` instead of `history`
         */
        <button onClick={() => {
            this.fakeAuth.signout(() => this.props.history.push('/foo'))
        }}>Sign out</button>
    }
}
icc97
  • 8,746
  • 6
  • 60
  • 75
  • 1
    What if I want to append to the current URL? Like if the current URL was `google.com/:search`, then I wanted to make it `google.com/:search/vendor`... or something. – Beulah Akindele Jun 15 '20 at 12:00
1

This is how I did a similar thing. I have tiles that are thumbnails to YouTube videos. When I click the tile, it redirects me to a 'player' page that uses the 'video_id' to render the correct video to the page.

<GridTile
  key={video_id}
  title={video_title}
  containerElement={<Link to={`/player/${video_id}`}/>}
 >

ETA: Sorry, just noticed that you didn't want to use the LINK or REDIRECT components for some reason. Maybe my answer will still help in some way. ; )