How to pass params from Route (react-router-dom) to render function - node.js

Is possible to do something like this:
<Route exact path="/activate/:token" render={this.activateAccount} />
then in same component
activateAccount(token) {
console.log(token);
return null;
}
How to pass token?
Is my logic correct? Learning MERN a bit, what I find confusing right now is how to move between backend and frontend, for example here when I generate activate account URL I have something like
http://localhost:5006/api/activate/8d7f5b25befb70045b5cb36893fa0f7688b85504
Now my NodeJS/Express is running on 5006 port and my ReactJS is on 3006, not sure what is logic here, I can finish everything on my NodeJS side in this case but not sure how to redirect later on to /login/ on frontend.
Thanks!

The parameter of activateAccount won't be token:
<Route exact path="/activate/:token" render={this.activateAccount} />
As the reference states, Route render function receives route props:
All three render methods will be passed the same three route props
match
location
history
Otherwise it wouldn't be impossible to make use of them in route component.
It is:
activateAccount(props) {
console.log(props.match.token);
return null;
}

Related

React Router v6 and ownParams doesnt work like v5

Hello in react router dom v5 i can get params inside redux. Sample code is below:
1- passing parameter
<Route path="/saveproduct/:productId" component={AddOrUpdateProduct} />
2- get params inside redux. I can get the productId inside ownProps
function mapStateToProps(state, ownProps) {...
But when i call route in v6 i cant get the productId inside ownProps
First, in react-router-dom v6 you should pass component to Route like an element. See docs.
<Route path="/saveproduct/:productId" element={ <AddOrUpdateProduct /> } />
Second,
react-router-dom v6 Route components rendered via the element prop don't receive route props
See question. Redux is not needed here. Just use params react hook
const { productId } = useParams();
Im new at react and it take my one day. But finally i found the solution. I am not sure this is the best practice but it make sense for me now. Check link for solution.
https://youtu.be/qdCHEUaFhBk
Also thanks #kupp

MongoDB, Node, Express, EJS - Pass a array/variable from backend to frontend (from route to client)

I've been trying to figure out a better way to push a variable from the backend to the frontend. Right now I do something like this.
I have a MVC-pattern, so when hitting the route
app.get('/fil', middleWare.isLoggedIn, user.fil)
... trough node does some querying the DB, and pass on the data.
exports.fil = async (req, res) => {
try {
faktura = await Lan.find().populate('client', 'namn kundnr')
res.status(200).render('pages/createInvoice', {
faktura: faktura
});
} catch (err) {
return res.status(500).send({
message: err.message || "Some error occurred while retrieving datas."
});
};
};
... it generates the page, with the help of EJS (i love EJS) and then pass it on to the client/user.
And in the .ejs-file that is served to the client/user I add the following
<script>
var fakturor = <%- JSON.stringify(faktura) %>;
</script>
which then means that I use up the variable and work with it with JS.
And this is where my question pops up. Is this a good way to do it or is there any other way to handle it?
I guess one idea is to let the user to query the DB straight from the page, but in my case I believe it wouldn't actually be better for the user to do so (the user will reieve like 100 different rows that they will be able to filter and then download a file of)
But is there any other ways I could do this without the script-tag? Like i said, I guess a ajax-call from JS/the client could be used but could you do it any other way? Can EJS do it any other way?
ejs is used for static pages mainly, if you want to build a dynamic page I would look for a single page application framework like angular and react.
if you still want to use ejs you can use ajax call to the server to load a variable from the DB.
I would never query directly from Front end to DB because then you are not controlling the security of the server, always go through the BE.
also try to think if you really need a variable in the front end, can you solve your problem using rendering only?

Redirect If Authenticated NodeJS

I am using the following tech
NodeJS
ExpressJS
VueJS
ngnix
i store the x-access-token in the localstorage.
When the user visits the site www.example.com a vuejs component does the following
Verifies if the user is logged in by calling an authentication endpoint
If verified, it redirects to www.example.com/controlpanel
Ofcourse the problem is it takes a while for the vuejs component to load and therefore the page loads and later is redirected.
Is there a way of handling the above scenario in a cleaner way. Using ngnix even?
Thanks
In the component which is rendered on the visit to homepage(root route /)
add a beforeRouteEnter() navigation guard as follows:
//in root route component options
beforeRouteEnter(to, from, next){
myAjax.get('/auth').then((res) => {
if(res.data.user){
//user logged in
next('/controlpanel');
}else{
next('/');
}
});
}
this guard is called before the route component is rendered and only gets confirmed and rendered if you invoke next()
keep in mind you will not have access to the compnents's vue instance as the component is not created yet
to get acceess to t vue instance inside beforeRouteEnter() do this:
beforeRouteEnter(to, from, next){
next(vm => {
//acess the component's instance using vm
}
}
For more info check out In-Component Guards

redux onEnter dispatch could work on server rendering?

i have a working client side app which uses redux-router.
i dispatch the initial state of user page from my api.
my routes file:
export default function ({ dispatch, getState }) {
function getUser(nextState, replaceState) {
dispatch(getUserData(nextState.params.id));
}
return (
<Route path="/" component={App}>
<Route path="user/:id" component={User} onEnter={getUser}/>
<Route path="*" component={NoMatch}/>
</Route>
);
}
}
so on the client it works great.
i would like to get my markup rendered-to-string after the getUserData dispatch is back with data.
thats my server matching and rendering (from the official server-rendering example):
app.use((req, res) => {
const store = reduxReactRouter({ routes, createHistory: createMemoryHistory })(createStore)(reducer);
const query = qs.stringify(req.query);
const url = req.path + (query.length ? '?' + query : '');
store.dispatch(match(url, (error, redirectLocation, routerState) => {
if (error) {
console.error('Router error:', error);
res.status(500).send(error.message);
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if (!routerState) {
res.status(400).send('Not Found');
} else {
res.status(200).send(getMarkup(store));
}
}));
});
is it possible to get this working while using onEnter?
or it only fires on the browser?
would appreciate any help guys!
thanks
I don't understand - I assume getUser is async, rendering is always synchronous in React. You'd have to get the data ahead of time. Relying on onEnter is a nice idea but it wouldn't work.
Basically...
First: you need to expose your methods that grab data so they can be called on the server outside of flux. The action/dispatcher/store doesn't work well on request/response cylce and make sure you have a file with API calls.
Second: put all your routes in a JSON file, React Router (or whatever router) reads that JSON and adds the routes in a loop with their handler, the server-side code reads those routes and adds express routes for the same routes pointing to the method, each route in the JSON also contains a reference to the data the component needs to a real initial render (what async calls). You create an empty copy of the initial state object, each handler on the express side performs all the calls to the relevant API methods (from the JSON) and when a Promise.all resolves on "getting the data and filling it in the state" resolves you render,
The render now contains the relevant data.
Third, you need to figure out how to pass state to the server, how the user is logged in, what they can do and so on - I recommend having a second server act as a cache since rendering is CPU bound in React so you need caching. We cache based on route, user status, device and a few other basic things.
Fourth, you point your non-rendering server (the caching one) to the rendering one and forward requests, hopefully requests should hit the cache, you need to have the non-rendering server "fall back" to client-side rendering only if the rendering server fails. This also lets you "hot swap" the rendering server on deploy.
You also need some way to deliver the JavaScript itself from the rendering server (so there is a single source of truth) that shouldn't be too big of an issue.
There are a lot more delicate parts in the flow - but that's pretty much how we do it and we have sub-second full renders which I think is nice. Went down from 5 seconds when our site was mostly Angular and rendered on the client.

Login/out react routing and expressjs routing

What im trying to do is Have a Log In page, a Sign up page. The login and signup work fine, they just perform whatever was written in express using passport. However what I want to do is make a route '/dashboard'. I did so and it's just a dashboard component made up of other components like a navbar and body/content. How do I write it in react router in such a way that it only allows me to access the route /dashboard if the user is authenticated. In express I would write a function like this :
function isLoggedIn(req, res, next) {
//if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next(); //cuz we want to move on incase we're stuck here
//if they arent redirect them to the home page
res.redirect('/');
}
However I didn't even write in the dashboard route in express. I only did it in react-router. My component hierarchy is like this right now
<App/>
<Dashboard/>
<NavBar/>
<NavMenu/>
<Body/>
<Login/>
<Signup/>
<About/>
And my routing is like this :
<Route>
<Route name ="signup" path="/signup" handler={Signup} />
<Route name ="login" path="/" handler={Login} />
<Route name ="app" path="/dashboard" handler={App} >
<Route name ="logout" path="/logout" handler={NavMenu} />
</Route>
</Route>
I don't understand if i'm grasping the concept right, but from what the webpage is displaying it doesn't seem like it. So basically at localhost:3000/ comes up the log in page, and I can toggle between that and the signup page completely fine, when the log in button is hit it uses express to login (it can use react-router to do it as well correct?), on success it goes to /dashboard (res.redirect('/dashboard') in express). It also seems as routes handled by react router has that single page app feel, whereas express it feels like i'm going to a new webpage (I'm guessing that happens because of react-router just changing the url and rendering the component we want?). In my NavMenu component I link the logout button Logout however the url changes to localhost:3000/logout and nothing happens.
I nested it under login so to get to dashboard and it's routehandler it has to go through the login.
<Login>
<App>
<RouteHandler>
<dashboard../>
<data../>
<etc../>

Resources