How can I refresh the whole react application and saving cached - node.js

I created mern stack react application, using nodejs and express as a server. I want to recieve cookie with jwt token from the server and afterwards refresh the whole page completely and save the cookie. I tried to refresh the page by using window.location.reload(false) and also useHistory.get(0) but both of them refresh the page endless times till I deleted the token and then it stoped refreshing. I also tried to write window.stop() right after window.location.reload(false) but then it did not refresh the window at all.
How an I refresh the whole window only once?
It is worth to mention that I don't have so much experience with react, so I would really appreciate your help.
Thank you.

React doesn't like when you refresh the page yourself. It prefers to handle that by itself. Using the useState hook will auto-refresh the page when the state changes but you can also use the useEffect hook to change the value without causing re-renders.
So what you might want to do is get the cookie, then use the setState you created and the change of value will cause a refresh, while also storing the cookie.

If you want to have the navbar and the page change based on login, you could just switch pages. So have one page where you login with one navbar, then, when logged in, change the page.
Heres an example for an easy way to switch between pages:
import {useState} from 'react';
import ReactDOM from 'react-dom/client';
function Index() {
const [login, setLogin] = useState(false)
if (login) {
return (
<div >
<h1> Logged in ! </h1>
</div>
)
} else {
return (
<div >
<button onClick={() => {
setLogin(true);
}>Login</button>
</div>
)
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( <Index/> );
This re-renders everything on the page when swapping
It is probably better to do it in a format like this though:
w3Schools Example with router

Related

How does serving different pages in React works?

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.

How to implement social logins in MEAN stack?

I have successfully implemented multiple social logins in Node JS.
I'm stuck with the implementation in MEAN stack.
The flow I have implemented till now:
Step 1:
Button in Angular. On Click, I'm calling an API in Node which returns the OAuth URL to which the user has to be forwarded.
Step2:
Once the user enters his correct credentials, access_token is generated and sent to callback URL in Node.
Step3:
I need to send a callback to Angular, whether access_token has been generated or not. I'm not sure as to how I should pass data to Angular Page.
Is this the right approach?
so i myself am doing a mean-stack social media project and i used oauth.io,
https://github.com/oauth-io/oauth-js
its really easy to use and implementable only thing you need to know is how to import a npm package in angular.
linkedin HTML component
<html>
<header>
</header>
<body>
<a (click)="linkedinConnector()" id="linkedin-button" class="btn btn-block btn-social btn-linkedin">
<i class="fa fa-linkedin"></i> Sign in with Linkedin
</a>
</body>
</html>
linkendin TS component
import { Component, OnInit } from '#angular/core';
import 'oauthio-web';
declare var OAuth: any;
#Component({
selector: 'app-linkedin-connector',
templateUrl: './linkedin-connector.component.html',
styleUrls: ['./linkedin-connector.component.css']
})
export class LinkedinConnectorComponent implements OnInit {
constructor(private api: ApiService) { }
ngOnInit() {}
public linkedinConnector() {
OAuth.initialize('OAUTH-IO PUBLIC KEY');
// Use popup for oauth
OAuth.popup('linkedin2').then(linkedin => {
console.log('linkedin:', linkedin.access_token);
linkedin.get('/v1/companies/[company-ID]/updates?format=json').then(data => {
//do with the data what you want
});
});
}
}
however im using pop-up instead of redirect.
they have redirect too so you can implement it using there documentation
http://docs.oauth.io/
There are two ways you can do it. One is using passport.js and using OIDC client. Here are the examples for both autentication
Passport.js implementation
Oidc implementation
So when the auth token is generated. You will redirect user to some callback url along with auth token. Your node server will be listening to that url and will store user session using some node library for sessions.
Along with it what you will do is you will do a res.redirect to url on which user will land if auth token is generated if not redirect him to some other url.
Say in your angular app you have two URLs login url, logged in url.
In case auth is success :
So if auth token is generated you will redirect user to logged in url and set a session cookie for the user.
In case auth fails :
If auth token is not generated you will redirect the user to login url with some error state as part of url query params. Something like /login?auth_error=true where you can handle auth_error appropriately and show on client.
From security perspective, write a middleware on your node layer that will validate all your api requests and check if users session cookie is valid or not else redirect him to login page.
Also in my opinion, there could be multiple approaches to do this but this is how I have implemented login in my applications. So this answer is from that perspective.
In Angular you can use already available libraries for that. No need to do it yourself.
Here you have links to two such libraries that are also OIDC certified:
angular-auth-oidc-client
angular-oauth2-oidc
I add also the link to the Google instructions for OIDC authentication where you have all the necessary information to configure the libraries to use the OIDC authentication from Google.
Check also this library angular-6-social-login which provides login for Google, Facebook and LinkedIn.
This are all open source so you can still do it yourself and use the libraries as samples for how to do it.

ComponentDidMount() in Server-side render

I'm trying to server-side render my webpage for better performance but am running into an issue where my page's components componentDidMount()s aren't getting called.
For example, this is my main template file:
import React from 'react';
import Cube from './components/Cube/Cube.jsx';
class Index extends React.Component {
render() {
return (
<html>
<head>
<title>{this.props.title}</title>
</head>
<body>
<Cube />
</body>
</html>
);
}
}
And my Cube.jsx:
import React from 'react';
class Cube extends React.Component {
componentDidMount() {
console.log("Hey!");
}
render() {
return (
<div>
<h1>Hello</h1>
</div>
);
}
}
export default Cube;
I'm not seeing "Hey!" getting logged out in my pm2 logs nor in my chrome console even though I'm seeing the <h1>Hello</h1> when the page loads. This is stopping me from having any sort of logic for my component.
How do I get around this problem and make my subcomponents's componentDidMount() get called? Note I'm using express-react-views for my server-side rendering.
I think the only lifecycle hook that will be called server side is componentWillMount as explained here
Even then you would not see output on Chrome's console. You are only likely to see it in your node logs.
Let me know if this answers your question.
Problem is as I my self found out few days ago using Next.js that React application is not mounted. What that means is that Server Side Rendering is exactly that. React app is 'rendered' aka static HTML file is created on the server, and served to the browser. But in that process React is not mounted and no hooks are fired. Maybe componentWillMount I am not sure and have not tested.

Don't redirect on POST express.js

I'm making a basic web app with Node.js and Express 4 and I'm trying to implement a "follow" function. I did some inspecting on the Github website and noticed it used a form with a follow button that would post to the server to follow a user. I think this sounds like a good approach but when I post I don't want to have to reload the page just like the github website.
How does one this inside of Express 4? Everything I put inside the .post route always end up in a page load. I'm pretty sure in jQuery's ajax method you can just return false and nothing will happen to the page, just the request will be sent which is what I want to happen because I'm using a RESTful api and I want to add the user to the current user's following but I don't want to have to use jQuery just for this function. I would prefer it be done in Express if possible, though any help would be appreciated.
views/user.handlebars
<h1>{{user.displayName}}</h1>
<p>#{{user.username}}</p>
<form action="" data-userid="{{user._id}}" method="post">
<button name="follow" type="submit">Follow</button>
</form>
routes/users.js
app.route('/:username')
.get(function(req, res) {
// get :username user from api and load info
...
})
.post(function(req, res) {
// don't reload page
???
// send PUT :username user to current users following array
...
});
So you're on the right track, but instead of putting your actions in the HTML (in your jade file) you're gonna have to add a script section to your jade and use javascript to attach an onClick event to the button so that when you press the button you invoke your ajax method.
Let me know if that doesn't make sense.

How to get localStorage before rendering reactjs components in universal app?

I am storing "some" user's session data in the client's localStorage, I need to get this data after server rendering and before the reactjs app is loaded so I can check if the user session is valid. If the user session is valid, I update the redux store with the user data; otherwise, I leave it as is.
I am using react-router's onEnter hook to check if the user's session is valid. The problem is that I am requesting the data saved in the localStorage on the server side (which I know is not available).
Therefore, I need a way to check the localStorage after the server render and have it ready for the onEnter hook.
I would also like to know if there is a way, while on the server side, to request the client's localStorage?
You will need to sort out the logic in between createStore and render() in your client.js file.
import {createStore} from 'redux';
const store = createStore();
if(localStorage.get('token')) {
store.dispatch(authenticate(localStorage.get('token')));
}
render(
<Provider store={store}><App/></Provider>,
document.getElementById('js-react')
);
Keep in mind that if there is any asynchronous code in the authenticate action creator that you will then need to wait for it to finish before you can render.

Resources