I'm trying to create a React application using Express as a back-end
I have this route set up in express
app.get('/manage/:id', (req, res) => {
// redirect to react application
});
I want to be able to make my React component get data from my database (to then use it), but I need the id for that.
Any suggestions on how I can access the :id in my React component?
Get the URL from the window.location object and parse it:
UPDATE: window.location.pathname.split('/').reverse()[0]
Related
This is a similar question but it provided solution for the specific issue of OP
I am trying to implement authentication in my React app using JWT. After logging in, server sends access token and refresh token. Access token expires shorty within an hour while refresh token is persistant for a year. Both are stored in localStorage.
I am using axios to make requests to server. I have created a file api.js that creates an axiosInstance which sets up baseURL for requests. This file exports this axios instance and every other component/ file that wants to use axios, imports it from this file - api.js. I have also set up an axios interceptor in the same file that will modify each request before sending it. It will basically add access token in authorization header if token has not expired, otherwise it will use refresh token to get new access token.
Now I have a TokenProvider Context that basically wraps whole app and it gives you token and a method to update this given token as well as the one in localstorage (useToken).
After i get the access token from the server with the help of refresh token, i want to update it in localstorage as well as the token that TokenProvider provides. I tried importing useToken from TokenProvider in api.js but React won't allow to use hooks in functions that are not components.
React Hook "useToken" is called in function "{functionName}" that is
neither a React function component nor a custom React Hook function.
React component names must start with an uppercase letter.
How should i go about implementing this functionality to update TokenProvider's token? Should i listen for events in TokenProvider that are trigged when localStorage updates or shoudl i try to convert api.js into some type of React component?
use forwardRef , read the docs here
Create function inside the components that call for your setStateName(),
and call it from the ref of your components
I'm new to the react world and to the fullstack world as a whole but I've searched endlessly for an answer to the following and some guidance would be really appreciated.
I'm creating an app using React and Express. It requires authentication so I was planning on using Passport to help. The client side JS uses React Routers to navigate through the website. That's all fine but my issue is with the initial GET request made by the browser.
I'll first describe my specific app requirements and then generalize what I don't understand.
As I said, my application requires OAuth2 authentication. If you try to GET a path on my website and you're not logged in, it should just load the login page. If you are logged in, then load as normal and find your path. Similar to facebook, I'd like the login URL to be the same as the "feed" page. So similar to how facebook.com '/' route is either the login page or your new feed depending on whether you are signed in, I want the same thing.
From what I understand, Passport authenticates on the back end by checking the request header. So I understand that I should have some kind of middleware that says "if user is signed in, continue down the routes otherwise render sign in page" ... How is this done? What would the code look like? My only experience with Express was from an intro class which used res.render to send back an HTML file and pass it through some template engine like handlebars. But I have no idea how it'd work with react routes. Would i still use res.render()? Something else?
Let's say my index.html has the root div to inject the react into. If I had to guess, I'd send back that index.html page with the .js file with the routes and somehow on the backend send back the route I want it to match on my react routes (either the login one or the user requested)??
More generally, I guess I'm just confused how the initial request to a website using react routes is done. 1) How does the server interact with everything to render what I asked for? 2) What would the code look like for that. My only experience with React is from a basic Udemy course that just used "react-scripts start" to render the page.
After spending the entire day Googling this question it led me to SSR which is a rabbit-hole of its own and I'm not even sure if its what I need to help me. Is it?
I'm clearly missing some fundamental knowledge as this is really tripping me up so if you have any resources to learn more just post them. Thanks!
I understand your struggle as I've had to go through it myself when combining front-end with back-end, specifically React and Node. So first things first, we know that the browser/client will always initiate a request to the server, so how does React Router take control of the routes? Well its plain simple actually, all you have to do is return the entire react app from any route from your express server. The code will look something like this:
const express = require('express');
const app = express();
app.get('/*', (req, res, next) => {
// Return React App index.html
});
app.listen(3000);
Once the react app renders on the user browser (don't worry about paths, as react will automatically render according to the URL based on the code you wrote in the client side, it will also take care of authentication vs feed page when it will scan for your local storage, cookies, etc), it will take control of routing, instead of a request going to the express server. But what happens when we request data from our server, well it returns react app on each route so we need to setup an api route to handle any data requests.
app.get('/api/v1/*', (req, res, next) {
// Return some data in json format
});
Hopefully, this gives you insight about what you were looking for.
I think the fundamental gap you're struggling with stems from that lot of those 'intro courses' shove the entire browser client into the application server to get things up and running quickly, as in, the Node server renders the entire React app AND operates as an API...
// Ajax request from React app to: http://example.com/api
app.use('/api/*'),()=> {
res.send({ <!-- some JSON object -->})
})
// User visits in browser: http://example.com/**/*
app.use('/*',()=>{
res.render(<!-- entire React App sent to browser -->)
})
The first request (assuming the user doesn't visit /api/* ) will just send down the React bundle. Further user navigation within the client would generally send XHR requests (or open WebSockets) from the React app to Express routes running on the same node program.
In many situations it makes sense to have these parts of your program separated, as by having react delivered from a completely different location than where it requests data. There's many reasons for this, but optimizing computing resources to their differing demands of CPU, memory, network .etc and manageability of code/deployment are the big reasons for me.
For example...
User visits: http://example.com *
Nginx, Apache, a 'cloud proxy' .etc direct the traffic to a static React bundle, which has no authentication and never makes contact with your Node server.
If the user has Authenticate previously they will have token in local storage (if you're using JWTs for Authentication) and your React app will be configured to always check for these tokens when you first it is initially loaded.
If the user has a token it will send an Ajax request in the background with the token as a Header Bearer and will send back user data, then redirect them to an 'Authenticated page' like the FB feed you mention.
If they don't have a token or the token Authentication fails then React will redirect them to the Login or Registration page
React
React basically high jacks the browser's native 'location' functionality (whats displayed after you domain name). So any events after the initial page load (buttons clicks and such) are handled entirely by React internally and uses those routes to determine what to display or what data to fetch from the API through Ajax (XHR).
If the user performs a hard page reload then that request will go back to the server and it will perform the whole cycle over again
React Router
Allows you to do 2 things simultaneously...
Manipulate the browser Location and History objects.
Use that History and Location information elsewhere by detecting changes and sending off events.
SSR
I've only toyed around with SSR so I can speak to it, but its provides extremely low latency for initial renders, doing it in 1 network request, so you want to use it areas of your program where thats important.
Not sure if this answers you question, but let me know if you would like me to elaborate on anything or provide some more detailed resources.
SSR is a little bit confuses for developer that has less experience, let forget it for now.
It will be more easier for you to assume that frontend JavaScript (React) and backend Javascript (NodeJS) are two separate apps, and they communicate to each other via API.
here the code that show Login component and Feed component depending on whether you are signed in
import React, { Component } from "react";
import axios from "axios";
class Home extends Component {
constructor() {
const accessToken = localStorage.getItem("accessToken");
this.state = {
accessToken,
feeds: []
};
}
componentDidMount() {
if (this.state.accessToken) {
axios(`api/feeds?accessToken=${this.state.accessToken}`).then(({ data }) => {
this.setState({
feeds: data
});
});
}
}
render() {
if (this.state.accessToken) {
return <FeedsComponent feeds={this.state.feeds} />;
}
return <LoginComponent />;
}
}
and this is your backend
const express = require("express");
const app = express();
app.get('/api/feeds', (req, res, ) => {
const feeds = [
{},
{}
]
res.status(200).json(feeds);
});
app.listen(3001);
just keep in mind that they are two separate apps, the can be in two different folder, different server, different port.
Simply point Express to the folder containing your React files or build files.
app.use(express.static(__dirname + '/dist'));
where 'dist' contains the build files
See docs for more details
I'm somewhat new to React, but wholly new to NextJS, which I'm trying to teach myself. I've been going through the NextJS 'getting started' tutorial, as well as looking at some other tutorials. I don't understand why there is a need to distinguish between client routes and routes on the server, that is, why the client route given as an example uses a query, whereas the server route does not. I know that I am not seeing the forest for the trees, so if anyone can point me in the right direction of 'grokking' NextJS routes, I'd appreciate it.
From this tutorial, on the client side we might have
<Link href={`/blog?slug=${slug}`} as={`/blog/${slug}`} prefetch>
...
</Link>
which requires us (it would seem) to set up an Express server and handle the route
/blog/:slug
OK. But why? Why isn't the local link simply
<Link href={`/blog/${slug}`} prefetch>
...
</Link>
? Or, alternatively, why doesn't NextJS handle server-side the route /blog?slug=${slug} ?
I can follow what the NextJS site 'getting started' tutorial (I input the code myself and test it) is doing, but as far as routing I am a bit lost as to what I'm doing and why. Clearly I am missing a crucial (and elementary) element here, and would appreciate clues as to the error of my ways.
If you look at the route
/blog/${slug}
Here slug can take different values as it a parameter. If you want NextJs to handle such routes you need to implement a route for each value that slug can take. For example.
/blog/slug1
/blog/slug2
/blog/slug3
And this number can grow very quickly. Hence we use an Express server so that we can intercept request to route /blog and pass slug as parameter to the blog page.
You do not need different client and server routes. That is not compulsory unless you are using client-side routing explained here, with dynamic routes.
If you do not want to use that you can switch for server-side routing with our old friend<a> which does not require separate links.
NextJS handles server-side route queries. Below is a simple example for that -
server.get("/dashboard", (req, res) => {
const actualPage = '/dashboard';
const queryParams = {
username: req.query.username
};
app.render(req, res, actualPage, queryParams);
});
In above example, when you open page - /dashboard?username=amit, you can get the value passed in URL query in your page which you can retrieve using - getInitialProps function.
To get data from URL query with server-side routing, you must create your page with getInitialProps function. Example is as below --
Dashboard.getInitialProps = async(ctx) => {
const query = ctx.query;
const username = query.username;
return {"username": username};
}
Above code sends data from url query as page props. Server returns that data to the page in req.
Now you must create _app page with getInitialProps function to make this work.
Server side rendering with react-router This documentation is not sufficient enough to understand how to use react-router 2 to render react components with different types of http request like get, post , put etc. on server side.
Writing in details how to server side render react & react-router application could be very big topic.
I will assume that you are experienced user and you know how to use expressjs and how to create react & react-router app.
when you render server side you can create separate server routers to map each frontend route or create one which will take all urls.
Latter case need just one server router.
Somewhere in the bottom of your server router (before errors routes) write:
app.use('/*', function(req, res){ ... });
this route will catch all urls.
First of all we need information about url. We don't need info about protocol or domain therefore we need only this:
var url = req.originalUrl;
Info about method (POST, GET, PUT, DELETE) we get from:
var method = req. method
If you want you can make separate routes and you would have:
app.post('/something', function(req, res) {...});
app.get('/something', function(req, res) {...});
It does not matter.
Second thing we don't use browser history for react-router! We have to use memory history.
Your history object:
var history = createMemoryHistory(req.originalUrl || '/');
And you pass history object to router.
I like to create my root component to accept as param history object.
And when I use it in frontend I pass browser history, and when I use it in server render I pass memory history.
Below very simple example how server side rendering route could look
(I used also ejs templates):
router.use('/*', function(req, res){
var history = createMemoryHistory(req.originalUrl || '/');
var initialState = {};
//do something with initialState according to url and request method
var staticHTML = ReactDOMServer.renderToString(
React.createFactory(App)({
history,
initialState
})
);
res.render('index', {
staticHTML,
initialState: JSON.stringify(initialState)
});
});
In this example you need to populate initState based on user url and request method. And your app should on start use that init data.
Server side rendering also works like charm if you use redux. Because we have one store and one init state object. You can then pass during rendering any basic values.
For example when you render list of objects then you take it in frontend and pass to init state and then render. Then rendered page will have values.
I'm working in react+react-router+redux+redux-react-router+expressjs example, it is not totally ready but works and you could see how I solved server rendering:
https://github.com/uhlryk/my-express-react-seed
Current situation:
frontend: React & React-Router
backend: Koa
app.use(mount('/graphql', graphqlHTTP({ schema: schema })));
app.use(mount('/api', api));
app.use(serve(__dirname + '../../public')); //serves static index.html
When I click on React Router's < Link > in the browser, every webpages shows.
Whenever I refresh the page or manually enter a link. I get a 'not found' page. There is no server side rendering going here by the way. How do I let React-Router handle routes not specified above, i.e. only on the client?
The server has to respond with something when the page is refreshed; in this case, it needs to respond with index.html so that the client-side application can boot, and then React Router can mount the right component based on the URL.
So, server-side, you need to tell Koa to serve index.html for every URL that doesn't already match any of the other routes.
Solution (based on the answer above)
import router from 'koa-router';
import sendfile from 'koa-sendfile';
//code to initialize router
//...
router.get('*', function* () {
let stats = yield* sendfile.call(this, pathToIndexHtml));
if (!this.status) this.throw(404)
})
Koa now serves index.html on every route that isn't specified. :)