3

I'm trying to use the back button from the browser so the user can go back smoothly in my react application. It works sometimes for specific components. For example it works when I go from Supervisores to Anfitrion, but It doesn't work when I go from Anfitrion to Suprvisores nor in any of the dynamic Routes. Here's what I have in my Router.

    <Router>

    <Switch>

            <Route exact path="/Anfitrion" component={PropiedadesRegistradas}/>
            <Route path='/AgregarPropiedad' component={AgregarPropiedad} />
            <Route path= "/AreasRegistradas/:propertyId" component={AreasRegistradas}/>
            <Route path= "/ItemsAreasRegistradas/:propertyId" component={ItemsAreasRegistradas}/>            
            <Route path="/ElementosDeArea/:areaId" component = {ElementosDeArea} />
            <Route path="/AgregarItems/:areaId/:propertyId" component = {AgregarItems} />
            <Route path="/AgregarArea/:propertyId" component = {AgregarArea} />

            <Route path="/supervisores" component={Supervisores}/>
            <Route path="/historial" component={Historial}/>
            <Route path="/desinfeccion" component={Desinfeccion}/>
            <Route path="/folios" component={Folios}/>    

            <Route path="/areasRegistradas" component={AreasRegistradas}/>
            <Route path= "/agregarSupervisor" component={AgregarSupervisor}/>
            <Route path="/detalle/:servicio/:hostId" component={Detalle} />
            <Route render={()=> <h3>Not found</h3>}/>

          </Switch>
    </Router>


And here's what I tried using the useHistory Hook, but it displays a black page when I click on the button:

import React from 'react'
import Button from '@material-ui/core/Button';
import { useHistory } from 'react-router-dom'



export default function AgregarItems({match}, props){
    let history = useHistory()
    return(
        <div>
        <Button onClick={() => history.goBack()}>Atrás</Button>
        </div>
    )
}

It also displays a blank page when I use the browser's back and fwd buttons. I was reading about history in React router but I haven't found anything useful yet and when I do it is for react Router v3.

Thanks for the help!

Im using:

  • "react-dom": "^16.13.1",
  • "react-router": "^5.2.0",
  • "react-router-dom": "^5.2.0",
lorenzoajt
  • 105
  • 2
  • 7
  • Need to double check this again on my end, but have you tried wrapping the component in `withRouter` Ex: `import { withRouter } from 'react-router-dom'; const AgregarItems = () => { history.goBack() } .... export default withRouter(AgregarItems);` – codingwithmanny Jul 16 '20 at 20:02

3 Answers3

1

I fixed this by removing turbolinks from my rails app. Credit: page is not rendering when I click back button with react-router

Hayden Linder
  • 393
  • 4
  • 10
0

Just did a test with CRA. Have a look and try this. You might not need to use withRouter

File: ./PageOne.js

import React from 'react';
import { Link } from 'react-router-dom'

const PageOne = props => <div><h1>Click below</h1><Link to="/page2">Page 2</Link></div>;

export default PageOne;

File: ./PageTwo.js

import React from 'react';

const PageTwo = props => <div><h1>Click Below</h1><button onClick={() => props.history.goBack()}>Go Back</button></div>;

export default PageTwo;

File: ./index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import PageOne from './PageOne';
import PageTwo from './PageTwo';

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Switch>
        <Route exact path="/" component={PageOne} />
        <Route exact path="/page2" component={PageTwo} />
      </Switch>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

========== UPDATE ==========

For route middlewares for roles as an abstracted <PrivateRoute>

Click the run code snippet below for this one to see how it can work for permissions.

// IMPORTS
const { useState } = React;
// StackOverflow only allows HashRouter
// But replace with BrowserRouter
const { HashRouter, Switch, Route, Link, Redirect } = ReactRouterDOM;

/**
 *
 */
const NotPermitted = props => <div><h1>Not Permitted</h1><p>You need to be</p> <code>admin@admin.com</code><p>&nbsp;</p><Link to="/">Go Back Home</Link></div>;

/**
 *
 */
const AdminOnly = props => <div><h1>Admin Only</h1><p>You should only see this is your email is "admin@admin.com"</p></div>;

/**
 *
 */
const Dashboard = props => <div><h1>Dashboard</h1><p>Links</p><ul><li><Link to="/private">Private Page</Link></li><li><Link to="/adminonly">Admin Only</Link></li></ul></div>;

/**
 *
 */
const Login = props => {
  const onSubmit = event => {
    event.preventDefault();
    if (props.login) {
      props.login({
        email: event.target.email.value,
        password: event.target.password.value
      });
    }
  }

  return <div>
    <h1>Login</h1>
    <form onSubmit={onSubmit}>
      <p><input type="text" name="email" placeholder="Email" /></p>
      <p><input type="password" name="password" placeholder="Password" /></p>
      <p><button type="submit">Submit</button></p>
    </form>
    </div>
}

/**
 *
 */
const PrivatePage = props => <div><h1>Private Page</h1><p>Anyone logged in can see this page.</p><Link to="/">Go Back Home</Link></div>;

/**
 *
 */
const PrivateRoute = props => {
  const { component: Component, permitted, user, ...rest } = props;
  return (
    <Route
      {...rest}
      render={(routeProps) => 
        user
          ? permitted
            ? <Component {...routeProps} />
            : <Redirect to="/notpermitted" />
          : <Redirect to="/login" />
      }
    />
  );
}

/**
 *
 */
const App = props => {
  const [user, setUser] = useState(null);
  
  const login = ({ email, password }) => {
    setUser({
      email,
    });
  }
  
  const logout = () => {
    setUser(null);
  }
  
  return <div>
      {user && <button onClick={logout}>Logout</button>}
      <Switch>
        <Route exact path="/" render={() => user ? <Redirect to="/dashboard" /> : <Redirect to="/login" />} />
        <Route exact path="/login" render={(routeProps) => !user ? <Login login={login} {...routeProps} /> : <Redirect to="/dashboard" />} />
        <PrivateRoute user={user} permitted={true} exact path="/dashboard" component={Dashboard} />
        <PrivateRoute user={user} permitted={user && user.email === 'admin@admin.com'} exact path="/adminonly" component={AdminOnly} />
        <PrivateRoute user={user} permitted={true} exact path="/private" component={PrivatePage} />
        <PrivateRoute user={user} permitted={true} exact path="/notpermitted" component={NotPermitted} />
      </Switch>
      <hr />
      {user && <p><small>Debug JSON</small></p>}
      {user && <pre><code>{JSON.stringify(user, null, ' ')}</code></pre>}
      <p><small>Redirect Tests</small></p>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/login">Login</Link></li>
        <li><Link to="/dashboard">Dashboard</Link></li>
        <li><Link to="/adminonly">Admin Only</Link></li>
        <li><Link to="/private">Private</Link></li> 
        <li><Link to="/notpermitted">Not Permitted</Link></li> 
      </ul>
  </div>
}

/**
 *
 */
const Index = props => {
  return <div>
    <HashRouter>
      <App />
    </HashRouter>
  </div>
}

ReactDOM.render(<Index />, document.querySelector('#root'));
body {
font-family: Arial, sans-serif;
padding: 20px;
margin: 0;
}

form {
display: block;
}

input {
  height: 40px;
  padding: 0 12px;
  border-radius: 4px;
  border: 1px solid #efefef;
  min-width: 200px;
}

button {
  display: block;
  height: 40px;
  padding: 0 20px;
  background: blue;
  color: white;
  border-radius: 4px;
  border: none;
}

pre {
display: block;
margin-top: 20px;
}

code {
display: block;
  background: #efefef;
  padding: 20px;
}

h1 {
  font-size: 21px;
  padding-bottom: 20px;
  border-bottom: 1px solid #efefef;
  margin-bottom: 20px;
}

hr {
border: none;
height: 1px;
background: #efefef;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/react-router/umd/react-router.min.js"></script>
<script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script>

<div id="root"></div>
codingwithmanny
  • 1,126
  • 8
  • 20
  • I tried this, actually I used **history.goBack()** to go from a component to the main component "/Anfitrion" and it works!, but for some reason it doesn't work if I want to go to somewhere else. – lorenzoajt Jul 16 '20 at 20:31
  • What do you mean by "going somewhere else" like going to different route? Example `history.push("/page3")` ? – codingwithmanny Jul 16 '20 at 20:47
  • exactly! I mean, I can do history.push() without problems, but when I click the back button on my browser, it displays a blank page – lorenzoajt Jul 16 '20 at 22:51
  • Is this local development (standard CRA), or a production build (yarn build... etc)? – codingwithmanny Jul 16 '20 at 23:48
  • I think it has to do with the authentication process before this. Because I am redirecting directly to "/Anfitrion". Any ideas on how to use react router after authentication? – lorenzoajt Jul 17 '20 at 00:04
  • It can depend on how you're doing your authentication. Are you using custom Private Routes, a ajax interceptor as a middleware, custom localStorage, or something else? – codingwithmanny Jul 17 '20 at 00:06
  • I'm using Auth0, the way I'm redirecting is: {userType === "Anfitrion" && } This is because I have 3 different roles in my app, It redirects without problems. I am not sure if this is the best way. – lorenzoajt Jul 17 '20 at 00:26
  • @lorenzoajt take a look above the **UPDATE** section to see how you could implement Routes with permissions with a wrapper for `Route` as `PrivateRoute`. – codingwithmanny Jul 17 '20 at 10:28
0

I know this question is old but I will post my answer since I had this problem and I would have liked to find easier the solution I'm about to post.

Use case: React as front-end, Ruby on Rails 6 as back-end.

If you press "back" in your browser and your React app renders a blank page, you have 2 solutions:

  1. Remove TurboLinks gem
  2. Tweak your app so it works with TurboLinks.

If you want to remove TurboLinks:

  1. Remove gem 'turbolinks', '~> 5' from Gemfile
  2. Remove //= require turbolinks from app/assets/javascript/application.js
  3. Remove , 'data-turbolinks-track': 'reload' (x2) from app/views/layouts/application.html.erb
  4. Run yarn remove turbolinks
  5. Run rails tmp:cache:clear

Step 4 is the main difference with Rails 5. Credits to this post.

If you want to keep TurboLinks

The index.js of your React app looks like this:

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <App />,
    document.body.appendChild(document.createElement('div')),
  )
})

And you have to make it looks like this:

document.addEventListener('turbolinks:load', () => {
  ReactDOM.render(
    <App />,
    document.body.appendChild(document.createElement('div')),
  )
})

Basically you are changing the event listener from DOMContentLoaded to turbolinks:load.

If you stop here, you will notice that now when you go back and forward in your app, the components get rendered multiple times on the same page.

To solve the issue, go into application.html.erb and into the <head> tag add this snippet of code

<meta name='turbolinks-cache-control' content='no-cache'>

Congratulations! Now your React on Rails app works with TurboLinks.

Luciano
  • 29
  • 1
  • 3