React-router server side match translated routes? - reactjs

I'm using react-router for server side rendering and I have locale information stored in a locales.json file. The locale information is only set after a response from an api call, which includes the current language, i.e. 'GB', 'NO', 'FR', etc., which then completes the server response and everything is fired through to the client in the correct language.
However, I'm using the react-router match method:
match({ routes, location: req.url }, (error, redirectLocation, renderProps) => { ... }
...and I need the routes to be based off the language from the api response, i.e.
// Route
<Route path={`:storeId/${locales[language].path}`} />
// locale.json
{
"GB": {
"path": "contact"
},
"NO": {
"path": "kontakt"
}
}
Is this approach possible? It's like I need to define routes after the api call is made, but to make the api call, I need routes defined.

Yes, I haven't tried your example specifically, but it is definitly possible to define routes from an api response and pass it to the "match" function.
You could try something as following:
function handleServerRendering(req, res) {
axios.get('http://localhost:3001/myCutomeRoutes')
.then(function(response){
const myRoutes = {
routes: response.data,
location: req.url
}
match(myRoutes, function(error, redirectLocation, routeContext) {
// WRITE YOUR CODE IN HERE...
})
})
.catch(function(err){
console.log('error', err);
})
}
As you can see, you firstly do an API call and then you pass the response.data to routes inside "myRoutes" constant

Related

Shallow routing using withRouter and custom server not working

Using withRouter as a wrapper with custom server, shallow routing doesn't seem to be working.
I currently use this method to change the route:
this.props.router.push({
pathname: currentPath,
query: currentQuery,
});
router prop comes from using withRouter to wrap my class component.
And couldn't figure where to put the shallow flag. So I switched to the method mentioned in the docs:
this.props.router.push('/post/[pid]?hello=123', '/post/abc?hello=123', { shallow: true })
So I did that manually, but I started getting 404s.
http://localhost:3000/_next/static/development/pages/search/%5Btype%5D/%5Bcat%5D/%5Barea%5D.js net::ERR_ABORTED 404 (Not Found)
decoded:
"http://localhost:3000/_next/static/development/pages/search/[type]/[cat]/[area].js"
I tried using :type instead of [type] but it also didn't work.
This is how it's configured on the server:
if ('/search/:type/:cat/:area' === route.path) {
return app.render(req, res, route.page);
}
Folder Structure:
/pages/search/index.js
I think this structure has something to do with the problem, since it's in the index.js and not just a plain file in the pages folder.
It should not reload the page while changing the route, that's the main thing I'm trying to accomplish.
I'm implementing SSR pagination, and I'm planning to use shallow routing to make page changes happen on the client instead of the server. Meaning achieve SSR on first load only, keep user in without refreshing.
I also tried this:
server.get('/search/:type/:cat/:area', (req, res) => {
console.log("reached here..."); // this gets logged
return app.render(
req,
res,
'/search/[type]/[cat]/[area]',
req.params
);
});
But I'm getting 404s, the page is not there now!
This also didn't work:
this.props.router.push(
`/search/[type]/[cat]/[area]?${stringifyQs(currentQuery)}`,
{
pathname: currentPath,
query: currentQuery,
},
{ shallow: true }
);
This should work:
server.js
server.get('/search/:type/:cat/:area', (req, res) => {
return app.render(req, res, '/search', {
...req.params,
...req.query,
});
});
pages/search/index.js
props.router.push(
'/search?type=foo&cat=bar&area=baz&counter=10',
'/search/foo/bar/baz?counter=10',
{ shallow: true }
);
Linked issue from GitHub

Accessing data inside my API with axios post request

I'm trying to send an object with my get request so I can use it to retrieve data from the backend like so:
axios.get('/', {
params: {
mainID: usersID.id,
otherID: usersID.otherID
}
});
Now at my API I want to access that params object, how do I do that?
router.get('/', (req, res) => {
//how to access params?
});
You can access the route parameters in Express by req.params
From the documentation:
Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values are populated in the req.params object, with the name of the route parameter specified in the path as their respective keys.
Route path: /users/:userId/books/:bookId
Request URL: http://localhost:3000/users/34/books/8989
req.params: { "userId": "34", "bookId": "8989" }
Take a look at the Route Parameters section at: https://expressjs.com/en/guide/routing.html
Hope this helps!

Fetching 301 Redirect Data In server.js (Express/NextJS)

I'm working on a project using express and next js and I've found a great example of how to setup an array of data for your redirects in your server.js file. However, if it is possible I would like to build a plugin within WordPress that will allow a user to submit data for redirects so that it could be managed by someone without technical knowledge. My question is, is it possible to fetch data within my server.js file to replace the data in this example?
const express = require('express')
const next = require('next')
const { join } = require('path')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
//This is the data I want to fetch through the WP Rest API
const redirects = [
{ from: '/old-link-1', to: '/new-link-1' },
{ from: '/old-link-2', to: 'https://externalsite.com/new-link-2' },
]
app.prepare().then(() => {
const server = express()
redirects.forEach(({ from, to, type = 301, method = 'get' }) => {
server[method](from, (req, res) => {
res.redirect(type, to)
})
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, err => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
Yes, I believe it's possible do do something like that.
This library would allow you to make an API request within express: https://github.com/request/request
Executed like so:
var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Print the google web page.
}
})
The next step would be to create an endpoint in wordpress with all of the 301's that you want to create:
function my_custom_endpoint(){
return 'Hey look, its some data';
}
// Register the rest route here.
add_action( 'rest_api_init', function () {
register_rest_route( 'yournamespace/v1', 'my_custom_endpoint',array(
'methods' => 'GET',
'callback' => 'my_custom_endpoint'
));
});
Good luck, and happy coding!
So, just incase anyone else stumbles upon the problem of programmatically adding redirects that originate on a WordPress install this is how it can be done. My tech stack is React, Next.js with an Express server pulling in data from a WordPress install that is living elsewhere in the webs.
WordPress:
1) Create a blank WordPress plugin (Google is your friend)
2) Create an activation hook within your plugin to create a database(Again, Google with 'to_url' and 'from_url' for each entry.
3) Register a Rest Route within plugin (Like described above with Tanner's answer)
This Rest Route should be pulling your info from the database and returning it as an array in this format:
[
{ 'from': '/about', 'to': '/about-us' },
{ 'from': '/test3', 'to': '/banks/testing-page' },
]
4) Create a plugin admin page with a form that allows the users to add entries to this database. As your database grows your response from the rest api will grow and your redirects will seamlessly be included in your project.
5) In your React server.js you're going to need the following setup
const request = require("request");
let redirects;
request('https://yourwebsite.com/wp-json/YOUR-ROUTE/v2/redirects', function (error, response, body) {
if (!error && response.statusCode == 200) {
redirects = JSON.parse(body);
}
})
redirects.forEach(({ from, to, type = 301, method = 'get' }) => {
server[method](from, (req, res) => {
res.redirect(type, to)
})
});
Caveats: Make sure when you're manipulating data with forms in php you're taking proper precautions to sanitize and escape everything.

How to handle dynamic route params using the fluxible-router

How can I access the dynamic navParams using the fluxible-router
For instance if I have a user component and I want to set the userId prop of the component based on the route
// configs/routes.js
module.exports = {
home: {
method: 'GET',
path: '/',
handler: require('../components/Home.jsx'),
// Executed on route match
action: require('../actions/loadHome')
},
user: {
method: 'GET',
path: '/user/:id',
handler: require('../components/User.jsx')
}
};
https://github.com/yahoo/fluxible-router/blob/master/docs/quick-start.md
How can I access that userId in the User.jsx component?
I assume you're using the fluxible-router here, generated apps usually do.
Every router call includes a Payload parameter:
module.exports = {
user: {
method: 'GET',
path: '/user/:id',
handler: require('../components/Home.jsx'),
action: function(context, payload, done) {
console.log( payload.toJS() );
context.executeAction(registerCollector, payload, done);
done();
}
}
};
More on where this parameter is created in the docs. But that parameter contains all your URL-parameters as a JSON object.
To access them you have to use the payload.toJS() function though. Which took me quite a while to find, since it's not emphasised in the docs.
To access them directly in the Component, use the handleRoute API.
That should solve your problem.

Backbone router: Assemble complete url from route and parameters

I'm using the 'before' function in Backbone's router to intercept route changes so I can check client side authentication:
routes() {
return {
'search/:query/:page': 'search',
};
}
before(route, args) {
if (!userModel.get("Authenticated")) {
//I'll do authentication logic here
return false;
}
}
After any authentication is done, I want to navigate to the original requested route.
Say my route is something like /search/somequery/1, the parameters in the before function will be:
route "search/:query/:page"
args ["somequery", "1"]
Is there an easy way to assemble the complete requested url so I can call
this.navigate(returnUrl)
after my authentication is done?

Resources