ReactJS - Serving different contents for different URL (route paths) so it looks like a multiple page application
Asked Answered
D

3

7

I'm from a Java background and new to ReactJS. So sorry if this is a dumb question, but I'be been stuck on this issue for a few days. Please help if you can.

My understanding is that react is for single-page apps. I've done some test development over the last couple of weeks and have been playing with Router etc. But I can't get my head around how you use react to create different content on different URLs. This is what I am trying to emulate:

  1. http://localhost:3000- a blank page with a Sign-in box
  2. http://localhost:3000/home - a dashboard with a menu bar across the top
  3. http://localhost:3000/about - a page with other information in but the same menu bar as 'home'

I don't want anyone to respond with details on how to create the components/layouts (I am very familiar with CSS, HTML, etc), what I don't understand is how to create a 'single-page app' with totally different content against different URLs (route paths).

If this was java, I would template the HTML and different pages would be served for different URLs. But that is server-side.

I've tried assigning a component to different routes: <Route path="/home" exact component = {Home} /> and building the content in that component but that doesn't work (I think I'm stuck in Java land and still thinking of 'serving' content).

When I look at Facebook (provider of React) it seems like all the menu actions along the top open in the same page, but I can not work out how different components can be hiding?? and appearing?? based on different routes clicked.

Maybe I've got this totally wrong and unique HTML pages are used for different routes??

Please let me know what best practice is and how I achieve this.

If you can point me to youtube videos or some simplified walk-throughs I would be very very grateful.

I've searched the web for things like "different react components on different routes", but haven't found anything that really shows how this works and what best practice is.

Dingus answered 6/2, 2020 at 19:53 Comment(4)
You need to look into react-router-dom which allows inside app content change based on url/routeYoumans
reacttraining.com/react-router/web/guides/quick-startYoumans
From the quick-start guide, am I right in thinking that if <Users /> and <About /> share a common component ( like a menu), then this will be returned in both of these components (i.e. that these tags represent the entirety of the root div of the page)?Dingus
That's is possible but that will cause code duplication. You cake move your navbar in main root component which is App in most cases.Youmans
Y
3

I've created a sandbox for React Router example code with very minimal code. I hope that will help to understand and you can play around. As you can see, I've move Navbar outside page level components

Here is the working example https://codesandbox.io/s/react-router-dom-example-8vcqu?from-embed

Adding some code from that example

import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Switch, Route, Redirect } from "react-router-dom";
import Home from "./Home";
import About from "./About";
import Contacts from "./Contacts";
import NavBar from "./Navbar";

Home() {
  return <h1>Home</h1>;
}

function About() {
  return <h1>About</h1>;
}

function Contacts() {
  return <h1>Contacts</h1>;
}

const NavBar = () => {
  return (
    <div className="navbar">
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/about">About</Link>
        </li>
        <li>
          <Link to="/contacts">Contacts</Link>
        </li>
      </ul>
    </div>
  );
};


const App = () => (
  <BrowserRouter>
    <NavBar />
    <Switch>
      <Route path="/" component={Home} exact />
      <Route path="/about" component={About} exact />
      <Route path="/contacts" component={Contacts} exact />
      <Redirect to="/" />
    </Switch>
  </BrowserRouter>
);

render(<App />, document.getElementById("root"));
Youmans answered 6/2, 2020 at 21:16 Comment(11)
Thanks, Zohaib, I think I was in the right direction but not thinking in React (I'm still thinking a bit traditional). Also thank you for the sandbox. I'll look through it in more detail tomorrow. I'm off to get some sleep.Dingus
Zohaib, I've worked through your code and it doesn't do what I wanted it to do. How do I make the menu change for the different 'pages'?Dingus
There are two ways. One to move Navbar inside each component with modified items and other option is to use custom logic in component to determine which items to show like login, logout etc.Youmans
Is React the wrong technology for what I am trying to do?Dingus
No, React is the best thing happened to wed development, super awesomeYoumans
I've updated the sandbox with some use cases, have a look codesandbox.io/s/react-router-dom-example-8s2j0Youmans
Thanks Zohaib, I think I'm getting now. Can I ask a few questions? In Index.js you pass data into the NavBar object:Dingus
Thanks Zohaib, I think I'm getting now. Can I ask a few questions? In Index.js you pass data into the NavBar object: <NavBar isLoggedIn={loggedIn} setLoggedIn={setLoggedIn} /> Then use this data in Navbar.js to update and change what is returned by the function. Is the general principle with React, that each React class occupies a <div>, or other HTML element, on the page and the content of that element is updated with each user action within that element. So if you want to show a picture at one time and a table at another, you need to define a 'render' method which...Dingus
...returns the picture depending on some state and the table based on some other state?Dingus
@AdamDavies I would suggest you to go through these tutorials for better understanding of React and how it works. it will take your 2-3 hours but you will not regret. youtube.com/…Youmans
Perfect. I will do that. Thank youDingus
C
6

TLDR:

You didn't get it wrong. The same HTML file is used to "serve" (or "render") different content for different routes. You probably need to double-check your component and router code, but the idea <Route path="/home" exact component={Home} /> is correct.


My long and boring answer

Some history and context:

As you mentioned, a couple of years ago, the common way to create a website was by setting up a server with some backend code that would, not only handle which HTML page should be displayed, but also what data would be displayed. Most of the operations would be done in the backend, and the frontend was only concerned about displaying data in a pleasant way.

With the advance of Javascript and its popularity, more operations started to be done in the frontend. And as the browsers become more powerful, more and more things can be done with Javascript. Sorting tables, filtering data and AJAX requests are some examples.

People started to modify the DOM (meaning that they were using Javascript, instead of a backend language, to change which data should be displayed and how they should be displayed.)

Single Page Application (IMHO):

The core idea of the Single Page Application (SPA) was to improve this process. Take ReactJS for example. The concept of it (in my own words) is:

"how can I quickly change the data that is displayed using less processing power and creating a better experience for the user?"

And the answer (also in my own words) was:

"let's only update elements on the screen that needs to be updated. Everything else will stay the same, so we don't need to re-render it."

For me, that means that a lot of applications could now use ReactJS (or Vue, Angular, etc) to be more powerful and user-friendly. But that also means that not every application should be built as a SPA. For me, there is still a lot of valid use in the "traditional" application where the backend still has a lot of control over the data.

Finally, you answer:

That said, I would say that the first thing to reflect on is, if you really need a SPA ;)

If you do, I see two ways of controlling which data should be displayed:

First, with a "Pure" conditional render:

This means a big if in your Javascript. For the sake of simplicity, here is an example:

var openMenu = "Home"

if (openMenu == "Home") {
   showHomePage()
} else if (openMenu == "About") {
   showAboutPage()
}

function showHomePage() {
   return <HomeComponent />
}

Second, with a router control

By using a react-router or things like that, you are actually "moving" your Javascript if statement to the URL, instead of a local variable 😉

Some people will disagree with this. Using URL to render specific content, may not be classified as a Single Page Application anymore since the initial idea is to control what is displayed in the screen through Javascript and not URLs.

Some people will agree, saying that different URLs will help with SEO, organization and allow users to bookmark or share links.


In the end, you just need to think about your page layout (or structure) and write that in HTML. Then, put an if statement around the parts that should change. Either like this:

<App>
    <Menu />
        {(openMenu == "Home") && <Home />}
        {(openMenu == "About") && <About />}
    <Footer />
</App>

or

<App>
    <Menu />
        <Router>
            <Route path="/home" component={Home} />
            <Route path="/about" component={About} />
        </Router>
    <Footer />
</App>

Hope that gives you a little more direction 😀

Convoluted answered 6/2, 2020 at 20:48 Comment(3)
Thanks, Bruno, I think I'm missing the concept of the component building themselves rather than the back-end 'serving' pages. It is, of course, the URL routing that confusing my simple brain. I'll refactor my SPA and see how I get on tomorrow. Thanks again.Dingus
Does the first option (with inline if) allow the user to use the "back" button in the browser, to go to the previous page?Kailakaile
Hi @aurelia, the answer is: maybe. The "back" button in the browser changes the actual URL in the address bar. So the only way to make the first approach (with inline if) work with the "back" button, is also change the URL (even if its just a parameter) to indicate that. But this would be hacky. If you want to user the browser navigation, its better to use react-router properly, with all the routes; since react-router manipualtes the history to keep things synced with the native browser navigation.Convoluted
Y
3

I've created a sandbox for React Router example code with very minimal code. I hope that will help to understand and you can play around. As you can see, I've move Navbar outside page level components

Here is the working example https://codesandbox.io/s/react-router-dom-example-8vcqu?from-embed

Adding some code from that example

import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Switch, Route, Redirect } from "react-router-dom";
import Home from "./Home";
import About from "./About";
import Contacts from "./Contacts";
import NavBar from "./Navbar";

Home() {
  return <h1>Home</h1>;
}

function About() {
  return <h1>About</h1>;
}

function Contacts() {
  return <h1>Contacts</h1>;
}

const NavBar = () => {
  return (
    <div className="navbar">
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/about">About</Link>
        </li>
        <li>
          <Link to="/contacts">Contacts</Link>
        </li>
      </ul>
    </div>
  );
};


const App = () => (
  <BrowserRouter>
    <NavBar />
    <Switch>
      <Route path="/" component={Home} exact />
      <Route path="/about" component={About} exact />
      <Route path="/contacts" component={Contacts} exact />
      <Redirect to="/" />
    </Switch>
  </BrowserRouter>
);

render(<App />, document.getElementById("root"));
Youmans answered 6/2, 2020 at 21:16 Comment(11)
Thanks, Zohaib, I think I was in the right direction but not thinking in React (I'm still thinking a bit traditional). Also thank you for the sandbox. I'll look through it in more detail tomorrow. I'm off to get some sleep.Dingus
Zohaib, I've worked through your code and it doesn't do what I wanted it to do. How do I make the menu change for the different 'pages'?Dingus
There are two ways. One to move Navbar inside each component with modified items and other option is to use custom logic in component to determine which items to show like login, logout etc.Youmans
Is React the wrong technology for what I am trying to do?Dingus
No, React is the best thing happened to wed development, super awesomeYoumans
I've updated the sandbox with some use cases, have a look codesandbox.io/s/react-router-dom-example-8s2j0Youmans
Thanks Zohaib, I think I'm getting now. Can I ask a few questions? In Index.js you pass data into the NavBar object:Dingus
Thanks Zohaib, I think I'm getting now. Can I ask a few questions? In Index.js you pass data into the NavBar object: <NavBar isLoggedIn={loggedIn} setLoggedIn={setLoggedIn} /> Then use this data in Navbar.js to update and change what is returned by the function. Is the general principle with React, that each React class occupies a <div>, or other HTML element, on the page and the content of that element is updated with each user action within that element. So if you want to show a picture at one time and a table at another, you need to define a 'render' method which...Dingus
...returns the picture depending on some state and the table based on some other state?Dingus
@AdamDavies I would suggest you to go through these tutorials for better understanding of React and how it works. it will take your 2-3 hours but you will not regret. youtube.com/…Youmans
Perfect. I will do that. Thank youDingus
S
0

you write your routing logic inside app.js or any file depending on your project. in index.js

 import React from "react"
    import ReactDOM from "react-dom"
    import {BrowserRouter} from "react-router"
    import App from "./App"

    ReactDom.render(<BrowserRouter><App/></BrowserRouter>,document.getElementById("root"))

BrowserRouter is hardcoded to expect an address. It is 100 percent designed completely hardcoded to look at the URL in the browser’s address bar. It reads URL and if it sees any Route that has same path with that URL, it injects the component of that Route into the html and ReactDom renders it.

Shell answered 8/2, 2020 at 21:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.