0

I am new to React and getting familiarize with React Router. I divided the application into 2 main route since each use a different style: the Splash path is when the user first enter which contain the Splashscreen, Login and Register page; the Menu path is shown after the user is logined. Currently I am working on the Splash route but stumble on a few problem. The Splashscreen contain 1 button that go to the Login Screen. When I click on the button it worked fined, but if I refresh the login page, go back to the Spashscreen and forward, or manually enter the address, the page turn out blank. I tried using HashRouter and it worked, but some suggested that it should only be used on Dev server and not production. I don't use Webpack so I cannot make historyApiFallback: true and the application is running on localhost. Below are my current code:

App.js:

import React from 'react';
import './App.css';
import SplashTemplate from './component/Template/SplashTemplate';
import {
  BrowserRouter as Router,
  Switch,
  Route
} from "react-router-dom";

function App() {
  return (
    <Router>
      <div className="App">
      <Switch>
        <Route path="/" exact={true}>
          <SplashTemplate/>
        </Route>
      </Switch>
      </div>
    </Router>
  );
}

export default App;

SplashTemplate.js:

import React from 'react';
import Splash from '../Splash/Splash';
import LoginForm from '../LoginForm/LoginForm';
import RegistrationForm from '../RegistrationForm/RegistrationForm';
import '../Template/SplashTemplate.css';
import { BrowserRouter, Route, Switch } from "react-router-dom";

function SplashTemplate() {
    return(
        <div className="background">
            <BrowserRouter>
                <Switch>
                    <Route exact path="/" component={Splash} />
                    <Route path="/login" component={LoginForm} />
                    <Route path="/register" component={RegistrationForm}/>
                </Switch>
            </BrowserRouter>
        </div>
    );
}

export default SplashTemplate;

Splash.js:

import React from 'react';
import {
    BrowserRouter as Router,
    Link
} from "react-router-dom";

function Splash() {
    return(
            <div className="container">
                        <Link to="/login">
                            <button className="splashButton">Login</button>
                        </Link>
            </div>
    );
}

export default Splash;

Anyone can suggest a solution? I have try the above mention but still not the answer I am looking for.

Update Thanks to Danilo Venticinque answer I have reformatted the App.js file to:

function App() {
  return (
    <Router>
      <div className="App">
      <Switch>
        <SplashTemplate>
          <Route exact path="/" component={Splash}/>
          <Route path="/login" component={LoginForm}/>
          <Route path="/register" component={RegistrationForm}/>
        </SplashTemplate>
        <MainTemplate>
          <Route path="/mainmenu" component={MainMenu}/>
        </MainTemplate>
      </Switch>
      </div>
    </Router>
  );
}

And changed the SplashTemplate.js to:

class SplashTemplate extends Component {
    render(){
        return(
            <div className="background">{this.props.children}</div>
        );
    };
}

It seem to work for the Splash path but now the problem show up in the Menu path where if the route is input manually (http://localhost:3000/mainmenu) the template for the Menu did not show up but instead the Splash template did. What am I doing wrong here?

user3676506
  • 102
  • 10

2 Answers2

0

Your problem is in the App.js routing. It's rendering the SplashTemplate component (which contains the other routes) only when the exact path is /. So, if you launch the page with /login, SplashTemplate doesn't get rendered (actually, nothing does) and there's no router to serve your other routes.

I would suggest moving the routes into a single component or changing the App.js routing logic so that it would still display SplashTemplate for /login and other desired routes.

daniloxxv
  • 817
  • 6
  • 10
  • any suggestion on how to accomplish these? For moving routes into a single component, that mean I define all route in a file and import it to ````App.js````? And for changing the routing logic, I am not sure what do you mean by displaying ````SplashTemplate```` for other desire routes? – user3676506 Sep 28 '20 at 07:09
  • As a short-term solution, replacing the code inside your `App.js` Switch with this: ` ` Should be enough to fix your problem. It would ensure that the `SplashTemplate` is always displayed, and then `SplashTemplate` would be able to display the correct component – daniloxxv Sep 28 '20 at 08:43
  • Thanks for the answer but I found another way that seem to work thanks to your previous answer. Now I am facing a similar problem and have updated the question. Can you take a look? – user3676506 Sep 28 '20 at 08:58
  • Your solution will always display the `SplashTemplate` component, so you'll always see the background. – daniloxxv Sep 28 '20 at 09:20
  • The routes should be direct children of `Switch`, otherwise you might get unwanted behaviour. – daniloxxv Sep 28 '20 at 09:21
  • Thank you. I have found my answer after some digging around and combining with the previous iteration. I will put the answer here for other to see. – user3676506 Sep 29 '20 at 04:09
0

So after digging around and following both React Router V4 Routers with Master Pages / Templates and React Router v5.0 Nested Routes I was able to come up with a solution. First, move all the Routing to a seperate file call Route.js and import it to App.js. Since we need to seperate the two path we will put the routing in 2 different functions and call them in a main function like below:

Route.js

...
function LayoutRoute() {
    return (
      <Switch>
        <Route path="/splash" component={SplashLayout} />
        <Route path="/main" component={MainLayout} />
        <Route path="/" component={NotFound} />
      </Switch>
    );
  }

function SplashLayout() {
    return (
      <SplashTemplate>
            <Route path="/splash/splash" exact component={Splash} />
            <Route path="/splash/login" exact component={LoginForm} />
            <Route path="/splash/register" exact component={RegistrationForm} />
            <Redirect from="/splash" to="/splash/splash" exact />
            <Route />
      </SplashTemplate>
    );
  }

function MainLayout() {
    return (
        <MainTemplate>
            <Route path="/main/menu" exact component={MainMenu} />
            <Redirect from="/main" to="/main/menu" exact />
            <Route />
        </MainTemplate>
        
    );
}

const NotFound = () => <h1>Not Found</h1>;

export default LayoutRoute;

The App.js can just call Route:

function App() {
  return (
    <Router>
      <LayoutRoute></LayoutRoute>
    </Router>
  );
}

And the Template file:

SplashTemplate.js

class SplashTemplate extends Component {
    render(){
        return(
            <div className="background">{this.props.children}</div>
        );
    };
}

This can help achive seperated Layout for each path of the website/app needed and make sure the page is rendered when entered manually or refresh.

user3676506
  • 102
  • 10