How does serving different pages in React works? - node.js

Let's say I have a react projects, and an Express server for serving my project, as follows(After building the project):
]
This way, only the index.html is served, isn't it? If the user routes to a different page, how is that page sent to him?

Routing in javascript is managed by using HTML5 push state. So every time you click a link and go to another route, the browser history and push state is being used. That's the basis for routing in almost of all the single page applications.
Until and unless you refresh the page, your request doesn't go to the server. Hence, index.html is served only once and after that the router (here the react-router) takes over and manages the routing in url using the history API of the browser.
Hope this helps !

That is done using react-router which manages the routing using the browser's History API.
This style of a website is called a single page application as opposed to a multi page application where the server sends different pages depending on the url you route to.

you can use react-router-dom like this
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/someurl" component={ComponentForSomeUrl}
</Switch>
and render it with BrowserRouter
but you can use something like history.push, in my opinion react-router-dom is really simple and better than react-router
you don't need to send html file to specific route, in case of react express is used for building API (in most cases)

In you React folder you want to do npm install --save react-router-dom.
So inside the React Router family of libraries, there is a couple of different dependencies you can possibly install.
Ensure you never install React Router by itself.
The react-router library as it is published on npm is the core library of everything inside the React Router general project.
So react-router has some core navigational logic inside of it. It decides how to work with React, how to change content out depending on different rules and some other low-level logic.
To gain some actual implementation as it works specifically in the browser, install react-router-dom.
So anytime you want to use React Router on a project to handle navigation, always install react-router-dom, not react-router.
There are other similarly named projects that you might think you need as well, react-router-native for use inside of React Native projects.
In web applications we make use of react-router-dom, we are not making native mobile apps.
React-router-native is for native mobile applications only.
For the browser you always want react-router-dom as opposed to react-router-native
So perhaps in your App.js component you want to set something up that looks like this:
import React from "react";
import { BrowserRouter, Route } from “react-router-dom”;
const App = () => {
return <div>App</div>;
};
export default App;
I also recommend if you are new to React Router to get familiar with it by setting up something temporary like so:
import React from "react";
import { BrowserRouter, Route } from “react-router-dom”;
const PageOne = () => {
return <div>PageOne</div>;
};
const PageTwo = () => {
return <div>PageTwo<button>Click Me</button></div>;
};
const App = () => {
return (
<div>
<BrowserRouter>
<div>
<Route path=“/” exact component={PageOne} />
<Route path=“/pagetwo” component={PageTwo} />
</div>
</BrowserRouter>
</div>
);
};
Visit your localhost:3000 and then your localhost:3000/pagetwo, check out how all that is working.
When we visit a page called localhost:3000 and we type that address into the url it loads up the application.
React Router itself does not care about that entire url, instead React Router only cares about all the characters that are listed after the domain name or port definition.
Localhost:3000 is interpreted as being localhost:3000/
If I go to localhost:3000/ it still loads up my application.
Now I have other examples here if I go to localhost:3000/pageone, React Router only cares about everything after the port and domain
Same thing if I went to airbnb.com/listings/spain react router would only consider /listings/spain when deciding what content to render to the screen.
Notice in the example above I created an instance of BrowserRouter, well BrowserRouter creates an object of its own known as the history object.
This history object is going to look at the URL inside the address bar and extract just that portion of the URL that react router cares about.
The history object is then going to communicate that path over to BrowserRouter who communicates that path to both Route components and those Route components decide whether to show themselves or hide themselves depending on the path that the user is visiting and the path property that it was passed when it was created.

Related

Add an express use handler that changes the base route

I have a svelte/sveltekit app. It says you could just your app like so
import { handler } from './build/handler.js';
app.use(handler);
But I already have another app in this express server, eg
app.use(otherhandler)
So I was hoping there was a way to do this
app.use('/newapp', svelte)
And it works, but, my svelte app has an auto redirect to /login if you are not logged in. So then the express app immediately redirects to /login whereas I was hoping it would go to /newapp/login. Is there a way to do this?
When you have a different base, you probably should configure that via config.kit.paths.base which then can be imported from $apps/path and added to the various links and redirects (at the very least in the UI this will be necessary, as stated by the docs).

Conditionally use next.js app or create react app with the same website domain according to users login

I have a website which I've built with CRA, node.js and I want to use ISR for most of the pages.
The problem is that about 20% of the users are registered users, which get their own content, and different header, which means I can only use SSR, and not ISR.
My thought is to use something like:
In my node.js server I would check if the user is logged
If he is not logged, I would send a get request to the next.js server, get the static html file and serve it.
If the user is logged I would just send him my CRA app.
Another option that I thought about is to use a proxy server with filter on the request which check if the session ID or cookie ID is set
Is it possible? Which option is better?
Shall I be able to use CDN to serve those static files?
Is there any better idea to solve this problem?
Just keep everything in the Nextjs application.
If you need static generated pages use getStaticProps and getStaticPaths or nothing (to have the same result as a CRA app) in that page.
If you need some server related logic use getServerSideProps in that page.
UPDATE
After run next build
The page test is a simple component
const Test = () => <div>test</div>;
export default Test;
In the other pages (/gpp, /gpp/[id]) getServerSideProps is defined
.....
const GppPage: NextPage = () => (
<>
<Head>
<title>GPP</title>
</Head>
<Box>
....
</Box>
</>
);
export async function getServerSideProps(context) {
return {
props: {
session: "mysession"
}
};
}
export default GppPage;
In the image the Test page is clearly a static page (look at symbols)
If you define in _app.tsx some getInitialProps or getServerSideProps in that case you will inherit the SSR behaviour
Instead of using next.js I ended up creating my own ISR for my website. This way I could use SSR for registered users and ISR for unregistered users. While using SSR in CRA app is not recommended by the create react app team, I found out that it is pretty simple with the help of this article for SSR, this article for SSR with react router. I used react 18 and react router 5.
While this solution worked for me, it is not guaranteed that it will work later so I won't recommend it until the create react app team will recommend it.
The pros of the solution:
More freedom with the code. For example, I could serve different pages for mobile and desktop (and still serve static pages).
Reduced costs compared to next.js
The cons of the solution
Unstable because the create react team doesn't recommend it
Missing out of some of the next.js features like images optimization
The html pages are not served from CDN (I used EBS)

React router 4 - Link to page outside react app

I'm building a node + react app that uses passport's facebook authentication. Getting this authentication to work involves hitting an express route '/auth/facebook'. Unfortunately as soon as the react app loads up react router 4 doesn't allow links to directly hit the express server and instead searches for a react route matching 'auth/facebook'. In short how do I link to a route within my application but outside of the react app when using react router 4?
React Router is only for client side routing. Use fetch API or a similar library for that.
I'll state one way of solving your problem (using fetch and without react router).
Remove the href from the <a> tag
Add an event listener for the click event, <a onClick={makeCall}>
Then in the makeCall function, you can call the backend using the fetch API(or axios or whatever),
makeCall() {
fetch('/auth/facebook', options)
.then((res) => {
// Something
})
.catch((err) => {
// handle error
});
}

React Routing vs Express Routing

Been watching alot of tutorials and i see that there is express routing as well as react routing.
Is the react routing for client and the node js routing for server (api?).
Wanting to know if someone could please clarify this as new to React, Node, Express.
Thanks
It is possible (and even recommended) to use both of them in combination.
TL;DR
react-router is used to navigate between multiples pages/views of your front-end app/website. Usually in a single page app (SPA), where pages/views are loaded dynamically.
express router is a way to return static content (index.html, image.png...) AND to handle API calls that are often related to database logic. Those routes are handled server-side.
Example
myapp.com/my-portfolio is a view and should be handled and rendered by react router
// this router render pages components dynamically based on the url
<Route path="/my-portfolio" component={Portfolio} />
<Route path="/page2" component={Page2} />
myapp.com/user/create or myapp.com/api/getMyJson is an api call that should be handled server-side by express router:
// app.js
// api call that return json data
// this is where I will usually return database content
app.get('/api/getMyJson', (req, res) => {
res.send('{"my_var":"value"}');
});
// api call that return the content of folder app/public where
// the index.html and static resources are usually exposed
app.use(express.static('app/public'))
Single page application workflow
The front-end (client browser) request the back-end (your server) for the application static content (myLogo.png, index.html...) usually served by express router
While the first page is loaded and the user begin to interact with the app, the front-end continues to load other pages in the background (lazy loading)
When the user navigate to another page (with react-router), the page is already loaded and the user is taken there without any further server call nor page reloading
On another hand, express router need to handle API calls like myapp.com/user/userId/get/notifications to get data that is not "static" like json data.
I'll try explain the difference through an example. Say we have a single page application built with react at www.example.com
React Routing
We hit www.example.com and the index.html is loaded from the server. Note that it has all of your react pages in your bundle.js file. You now click the about button on the navbar, this sends you to www.example.com/about. This call does not hit the server, it is handled by your react router.
Express
Much like above we hit www.example.com and get the index. This time when we hit /about we get information from the server
Take a look at this blog post:https://medium.com/airbnb-engineering/isomorphic-javascript-the-future-of-web-apps-10882b7a2ebc

Ember and Express: let Ember handle routes instead of Express?

This might be a dumb question, but I'm serving an Ember app I made using ember-cli on an Express server, but when I try to access various routes, my Express app errors, saying that no route exists (which is true, because I defined the routes in Ember, not Express). How should I resolve this, and is this normal behavior?
My Ember router:
Router.map(function() {
this.route('index', {path: '/' });
this.route('portkey');
this.route('login');
});
My Express routes are just an API that do not serve any of the Ember routes, since localhost:1234 will automatically load index.html.
I've never had a problem using the Ember Router instead of the Express router. All I do is have 1 express route (for '/') which displays my Ember application index.html (well actually index.ejs) page. Not promising this is the right way to do it, but it's how I do it and it works for me.
So start with this.
app.get('/', function(req, res) {
res.render('index', {});
});
That's your express route. Now your ember routing.
App.Router.map( function() {
this.route("about", { path: "/about" });
this.route("favorites", { path: "/favorites" });
});
So as of now you have a routing structure that looks like the following:
yourdomain.com/ --> index.ejs displayed via express routing
/#/ --> this is the ember index route
/#/about --> this is the ember about route
/#/favorites --> this is the ember favorites route
Within the index.ejs file you have the basic ember file linking to your ember application.
Now onto your linking problems...
If you use the ember router, then make sure you are linking to your different routes the correct way. (Remember, ember routes start with /#/someroute).
So your links in handlebars should be something like:
{{#link-to 'some_page'}}Go to some page{{/link}}
NOT
Go to some page
Using the second, express would be trying to handle the routing but by using the first, ember is handling the routing.
So if you really think about it, you can have as many ember applications as your little heart disires because each ember application is linked to that current page in the express routing.
For example on my website, I use two routes (plus a bunch of REST routes obviously): login.ejs and index.ejs.
So for my site, I have the following routes:
mysite.com/
/#/
/#/budget
/#/history
/#/profile
/#/logout
mysite.com/login#/
#/register
#/forget
I hope this helps you a little bit.
EDIT
/#/ is a convention to tell ember you are routing via its router.
Think of it like this: Ember is a single-page framework. So when you link from page to page in ember, you aren't truely changing pages. You are just removing dom elements and replacing them with new ones. But if you go to /budget on the server, you are now going to a whole new page, not just the /#/budget section of the ember application.
I think you are just confusing what the ember router really is.
I had similar issues when trying to directly access any part of my Ember project other than index.html. From there I could easily navigate where I wanted, but it meant that providing someone a link or refreshing the page would fail.
Example: /accounts would fail.
/#/accounts would successfully redirect to /accounts however refreshing still would not work.
Solution:
Router.map(function() {
this.route('accounts');
});
Router.reopen({
location: 'hash'
});
Now all of my links are prefixed with # such as /#/accounts, refreshing and direct-linking works as expected.

Resources