Nextjs How to map multiple routes to one page? - reactjs

I have a page called blog in my nextjs version 9.
Next create a route /blog for my page. Now I want to have these routes to be mapped to the same blog page and consequently the blog component:
1. /blog/cat1/gold
2. /blog/cat2/silver
3. /blog/cat3/bronze
Actually, I want to use them as query parameters in the route but I don't want to follow this format:
1. /blog?cat=cat1&color=gold
2. /blog?cat=cat2&color=silver
3. /blog?cat=cat3&color=bronze
I used next/router asPath but it is completely client-side and by reloading it returns 404!
In nextjs 9 dynamic routing has provided which may help me but the thing is I want to have only one component and different routes.
Do you have any ideas?

You didn't specify your web server, so I will give an example using expressjs.
const app = next({ dev })
app.prepare().then(() => {
const server = express();
server.get("/blog/:cat/:color", (req, res) => app.render(req, res, `/blog`));
})
If you need to access the value in the page, you can use getInitialProps to get the value by accessing req.params.cat and req.params.color.
Another way is by passing the value directly when calling app.render function:
app.render(req, res, '/posts', { cat: req.params.cat, color: req.params.color })
Here is the example.

You can do this with Next's dynamic routers. Just create a folder for blog-posts and add a dynamic page under it like this:
/pages/blog/[...slug].tsx
Now on your [...slug].tsx will catch all paths, no matter in what depth. And you can catch the path params from the router's query -field. Try this with any path under /blog/**/* -path and it will list path elements:
const Blog = () => {
const {
query: { slug }
} = useRouter();
return (
<ul>
{query.slug.map(value => <li key={value}>{value}</li>)}
</ul>
);
}

Related

Can I use Next.js Link to navigate from slug page to the default one?

So I have the default page and some 'slug' dynamic pages, the urls look like this:
default page locally: localhost:3000/doc/default
slug page locally: localhost:3000/doc/[slug]
default page in production: default.com/doc
slug page in production: [slug].default.com/doc
The link I need should be inside the slug pages and lead to the default one. So far I tried getting the basePath from nextRouter to use as a href. But that returns the slug url ([slug].default.com/doc.
Can I use the Next.js Link component and point it to /doc/default? It works locally, but I don't want to push it to dev/prod just to test if it works.
Have you tried redirects?
Next.js has an experimental a feature to redirect pages ahead of time inside its next.config.js file.
Let's say we'd like to redirect our root path site.com/ to site.com/en-us/. We could use useRouter whenever we needed to redirect the user or we could add directly into next.config.js:
const nextConfig = {
async redirects() {
return [
{
source: '/',
permanent: false,
destination: '/en-us',
},
]
}
}
Now anytime the user navigates to site.com/ he'll be redirected to site.com/en-us/ which will render the page inside pages/en-us/index.(jsx|tsx|mdx). It is also possible to use RegEx for matching as described on this issue.
For your use case, would be the the other way around. We'd probably have to use absolute paths, since we're redirecting to another domain. In this case, a subdomain of our root default.com domain.
// const getSlugs = fs.readdir(path.resolve(...), () => {})
const slugs = ['slug1', 'slug2']
const slugRedirects = slugs.map(slug => ({
source: `/doc/${slug}`,
destination: `https://${slug}.default.com/doc`,
permanent: false
}))
const nextConfig = {
async redirects () {
return [...slugRedirects]
}
}
module.exports = nextConfig
Now, whenever the user navigates to www.default.com/doc/slug1, either by typing the URL or clicking on a button that points to the pages/doc/[slug] pages, he will be redirected to slug1.default.com/doc.
Let me know if that helps. Cheers!

Redirect an array of URLs in Express JS

I want to assign an array of URLs from a React app (using Express server side rendering) and assign 301 redirects to each URL.
The slug/id format is changing and I need a way to ensure old links already indexed by Google our saved in the wild have a way to find their way to the new URL format.
This function will be a one-time use, as new URLs will follow the new slug/id format, but the redirects need to remain so that they can continue their redirects.
I know how to assign a single redirect to one URL using res.redirect but not an entire array.
(This is my first SO post. Tried to explain this as well as I can but apologies if there are gaps).
You can use a loop to create router.get functions, so something like:
const urls = ['/url1', '/url2', '/url3'];
urls.forEach(url => {
router.get(url, (req, res, next) => {
res.redirect(301, '/redirected-route');
})
)};
If they all need to go to different URLs rather than all to the same one, then you can define the redirect array as an array of objects with oldUrl, and newUrl properties to create a more dynamic redirect.
const urls = [
{ oldUrl: '/url1', newUrl: '/new-url1' },
{ oldUrl: '/url2', newUrl: '/new-url2' },
{ oldUrl: '/url3', newUrl: '/new-url3' }
];
urls.forEach(url => {
router.get(url.oldUrl, (req, res, next) => {
res.redirect(301, url.newUrl);
})
)};

Next.js How to make a redirect correctly

I have such a page structure.
locale can be any value from the language-country pair
eg en-ca, fr-fr, ar-en
[locale] // main folder route
page1.tsx // child route
page2.tsx // child route
page3.tsx // child route
For example, if I go to the address /page1, then I redirect to /locale/page1
But the problem is that I check on the browser side and first a 404 page appears in the browser and only then redirects to the correct address.
I think that it is necessary to check on the server.
I was making my own file for the server. But the problem is that there is no way to track the address for which the request is going and that means I cannot check if the address starts with the parameter I need.
In case you do not wont to use Next.js native i18n routing you can create fallback page file pages/[...fallback].ts to catch all non-existing page. Then you can use use getServerSideProps to redirect properly.
This could work for you (not tested):
// The page content will never be rendered
const FallbackPage = () => <div>Redirecting...</div>
// Is processed on every request on server side
export const getServerSideProps: GetServerSideProps = async (ctx) => {
// TODO: add custom detection (e.g. based on headers or cookies)
const locale = 'en'
const destination = `/${locale}/${ctx.params.fallback.join('/')}`
return {
props: {},
redirect: { destination, permanent: false },
}
}
export default FallbackPage

Route - Redirection (Next JS)

I am moving my website (PHP) to Next JS but I have a question regarding routes.
Currently I have this kind of routing (unique ID and slug from an API):
www.website.com/section/id_slug-of-post
And I manage some implementations, like:
www.website.com/section/id => 301 to www.website.com/section/id_slug-of-post
www.website.com/section/id_slug-with-wrong-words => 301 to www.website.com/section/id_slug-of-post
www.website.com/section/wrong-id => 301 to www.website.com/section
Can I do the same thing with Next JS or shall I use Express JS?
A feature like this is currently being discussed in this RFC on the Next.js GitHub. However, there is also a way to do this using the res.writeHead method in getServerSideProps
export const getServerSideProps = (ctx) => {
ctx.res.writeHead(301, { Location: '/new/url' });
}
You could also redirect on the client side using the Router instance provided by next/router.

How to create dynamic route in gatsby

I have setup gatsby project using this link. It is working correctly.
Now I know how to create route by defining the component inside the pages folder. But now I have a new challenge I need to create one dynamic route so that I can pass my id in it (Just like reactjs).
<Route path: "/path/:id"/>
How do I do that in gatsby?
You have to explicitly tell gatsby that a path should be dynamic. From the docs:
// gatsby-node.js
// Implement the Gatsby API “onCreatePage”. This is
// called after every page is created.
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
// page.matchPath is a special key that's used for matching pages
// only on the client.
if (page.path.match(/^\/app/)) {
page.matchPath = "/app/*"
// Update the page.
createPage(page)
}
}
and then you can use dynamic routing in src/pages/app.js
import { Router } from "#reach/router"
const SomeSubPage = props => {
return <div>Hi from SubPage with id: {props.id}</div>
}
const App = () => (
<Layout>
<Link to="/app/1">First item</Link>{" "}
<Link to="/app/2">Second item</Link>{" "}
<Router>
// ...dynamic routes here
<SomeSubPage path="/app/:id" />
</Router>
</Layout>
)
export default App
Everything that goes to /app/* will be handled dynamically now. You should find your id as usual in the props.
Have a look at their authentication example https://github.com/gatsbyjs/gatsby/tree/master/examples/simple-auth
You can use square brackets ([ ]) in the file path to mark any dynamic segments of the URL. For example, in order to edit a user, you might want a route like /user/:id to fetch the data for whatever id is passed into the URL.
src/pages/users/[id].js will generate a route like /users/:id
src/pages/users/[id]/group/[groupId].js will generate a route like /users/:id/group/:groupId
Reference: https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api#creating-client-only-routes
You can use gatsby-plugin-create-client-paths. It uses matchPath. For more info check
https://www.gatsbyjs.org/docs/gatsby-internals-terminology/#matchpath
https://www.gatsbyjs.org/packages/gatsby-plugin-create-client-paths/
This answer is Super late, but for anyone in the future who is faced with this problem, I have a simpler solution.
In Gatsby terms it's called a Splat Route.
For examples, If you want some page "domain.com/profile/[id]", where id can be any number, which will be used to display different data inside the website, you should name your page as [...id].
Now inside the page you can access this id as
const ProfilePage = (props) => <div>This page is for id number {props.params.id}</div>
Note: Don't miss the 3 dots, that is what signifies a splat route in gatsby.

Resources