nextjs links without strings - next.js

Im new to nextjs, and Im checking if it will be good for the app that will have pretty complex and messy internal navigation. Just checked their documentation and I see that they recommend usage
of Link component like this <Link href="/your_path">Path</Link>. A bit scary is that I have to provide 'your_path' as a string so every time i change page file name I have to manually update code that redirects to this page. Is there any solution that allows me to define routing on my own so I can write something like (pseudocode)
routes = [
...
{
page : 'page_name',
path : 'path_to_page'
}
...
]
So instead of using string I can do <Link href="{route.path}">Path</Link> or Im condemned to use this file-system based router with all consequences?

The simple answer is yes!
When you want to change a user route in NextJs you have 2 options,
The first is with the <Link> Element that you can specify a href to where it directs.
And you also have a useRouter hook for more complex routing for example if the user does an action that requires moving him into a different route you can do it internally in your handlers.
For more information about useRouter hook.
What I usually do is storing my routes in an object
const ROUTES = {
HOME: "/",
ABOUT: "/about"
}
and wherever you call routes you just use the object so F.E
With Link tag
<Link href={ROUTES.ABOUT}>ABOUT PAGE</Link>`
with useRouter hook
// Inside a React Component
const router = useRouter();
const handleNavigateToAbout = () => {
router.push(ROUTES.ABOUT);
}
return (
// SOME JSX
<button onClick={handleNavigateToAbout}> Go to about page! </button>
)

Related

how to pass data with next router without showing it in the URL?

I am using next router and I want to pass data to another page but I don't want the data to be shown in the URL
I am new to nextjs and I want to navigate between pages using router.push(). I found this solution in the official documentation
Let's say that I have a button once clicked I want ton navigate to another page and pass an object myObject to it.
import { useRouter } from "next/router";
const router = useRouter();
const myObject = {
proprety1: "example1",
proprety2: "example2",
proprety3: "example3"
}
<button>
onClick={()=>{
router.push({
pathname: '/next-page',
query: { data: JSON.stringify(myObject) },
})
}}
</button>
then in the next-page I get this as URL :
http://localhost:3000/next-page?data=%7B"proprety1"%3A"example1"%2C"proprety2"%3A"example2"%2C"proprety3"%3A"example3"%7D
this works fine to be clear, but it is really ugly, not just that, I don't want data to be showen to users.
is there another solution for this? thank you in advance
I believe you can use the second parameter as in the router.push function in order to accomplish what you want.
router.push(url, as, options)
See documentation.

NextJS - Add <Head> Data on query parameters

All my pages are working with getStaticProps.
I want to make "If there's and q parameter on URL, then add 'noindex' to ".
But as you can understand, that doesnt work on 'prerendered' pages.
But I have to find a way.
I need to add 'noindex' to all my 'shop?q=blabla' pages.
On _app.js I did like that:
function MyApp({ Component, pageProps }) {
const router = useRouter()
...
return (
<Fragment>
<Head>
...
{router.query.q ? <meta name="robots" content="noindex"></meta> : '' }
...
But not working on getStaticProps pages.
Is there any advice about it?
How can I automatically add 'noindex' to all of the 'q' parametered pages?
You'd need to create two different pages. One for the basic non query routing and the other for dynamic routing and use getStaticPaths for the latter.
nextjs documentation

NextJS route gives 404 when not using Link

I have a Next.js page, where the pages are statically generated (using next export). It's a dynamic route, but I will only fetch data on the client after the initial page load (in a useEffect).
The path is something like: /pages/foo/[id].tsx. This is in fact the only route which is going to exist.
My problem is:
If I access the URL directly (e.g. typing in https://mysite.fake/foo/1337 into the URL bar) I get a 404.
If I navigate to that route using a <Link /> it does work as expected
If I then reload the page, I get a 404 again.
On local dev, it works fine. The problem only exists when deployed.
The page in question is using the router.query, but I have the same problem with a completely static page (e.g. just /pages/bar/baz.tsx).
Example:
export const Home: NextPage = () => {
const router = useRouter()
const { id } = router.query
const headerText = id ? `Hello ${id.toString()}` : ''
// in a later iteration, I will use the query id to fetch data in a useEffect
return <h1>{headerText}</h1>
}
As far as I understand from the Next.js documentation on dynamic routing and data fetching this should be possible to do.
My next.config.js is very bare:
/** #type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
}
What am I doing wrong?

How to dynamically create subpages/subroutes in NextJS?

I want to create subpages dynamically like
example.com/test/index1
example.com/test/index2
example.com/test/index3
example.com/test/index4
.......
or something like this
example.com/test/[index1]
example.com/test/[index2]
example.com/test/[index3]
The subpages should be created based on the number of indexes. in the base/parent page
I am totally unable to figure out a way to handle something like this
Help would be much appreciated
Nextjs has file system based routing. To create a dynamic route for the app you just need to create a js/ts file with a name similar to [slug].js(where slug will be the route param for the dynamic route) in the pages directory. In that file, you can write all the logic for data-fetching and export a React component as default export which will be used to render the page.
For your use case, the directory structure and some pseudo-code for the page might look something like this
// directory structure
- pages/
- test/
- [slug].js
In [slug].js The example below uses getServerSideProps as data-fetching method which will be used to fetch the data required for the page on request for that page from a client.
// data-fetching methods
export const getServerSideProps = async (ctx) => {
// you have access to the route param slug in the ctx object
const slug = ctx.params.slug
// fetch the data required for the page by a database query or from a remote API
// return the fetched data as props
return {
props: /* fetched-data */
}
}
// the page component
const SomeDynamicPage = (props) => {
// props will contain the data that was returned from the data-fetching method-
// getServerSideProps
return (
<>
<h1>Some page</h1>
<div>
/* some content based on the received props*/
</div>
</>
)
}
export default SomeDynamicPage;
There are additional data-fetching methods (getStaticProps, getStaticPaths, getInitialProps) which may be useful depending on different use cases. Read more about data-fetching and dynamic routes in nextjs docs.

How can I change the subscriptions query parameters in react-komposer (meteor) from a child component?

I'm building an app with Meteor using the react-komposer package. It is very simple: There's a top-level component (App) containing a search form and a list of results. The list gets its entries through the props, provided by the komposer container (AppContainer). It works perfectly well, until I try to implement the search, to narrow down the results displayed in the list.
This is the code I've started with (AppContainer.jsx):
import { Meteor } from 'meteor/meteor';
import { composeWithTracker } from 'react-komposer';
import React, { Component } from 'react';
import Entries from '../api/entries.js';
import App from '../ui/App.jsx';
function composer(props, onData) {
if (Meteor.subscribe('entries').ready()) {
const entries = Entries.find({}).fetch();
onData(null, {entries});
};
};
export default composeWithTracker(composer)(App);
App simply renders out the whole list of entries.
What I'd like to achieve, is to pass query parameters to Entries.find({}).fetch(); with data coming from the App component (captured via a text input e.g.).
In other words: How can I feed a parameter into the AppContainer from the App (child) component, in order to search for specific entries and ultimately re-render the corresponding results?
To further clarify, here is the code for App.jsx:
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<div>
<form>
<input type="text" placeholder="Search" />
</form>
<ul>
{this.props.entries.map((entry) => (
<li key={entry._id}>{entry.name}</li>
))}
</ul>
</div>
);
}
}
Thanks in advance!
I was going to write a comment for this to clarify on nupac's answer, but the amount of characters was too restrictive.
The sample code you're looking for is in the search tutorial link provided by nupac. Here is the composer function with the corresponding changes:
function composer(props, onData) {
if (Meteor.subscribe('entries', Session.get("searchValues")).ready()) {
const entries = Entries.find({}).fetch();
onData(null, {entries});
};
};
The solution is the session package. You may need to add it to your packages file and it should be available without having to import it. Otherwise try with import { Session } from 'meteor/session';
You just need to set the session when submitting the search form. Like this for instance:
Session.set("searchValues", {
key: value
});
The subscription will fetch the data automatically every time the specific session value changes.
Finally, you'll be able to access the values in the publish method on the server side:
Meteor.publish('entries', (query) => {
if (query) {
return Entries.find(query);
} else {
return Entries.find();
}
});
Hope this helps. If that's not the case, just let me know.
There are 2 approaches that you can take.
The Subscription way,
The Meteor.call way,
The Subscription way
It involves you setting a property that you fetch from the url. So you setup your routes to send a query property to you Component.Your component uses that property as a param to send to your publication and only subscribe to stuff that fits the search criteria. Then you put your query in your fetch statement and render the result.
The Meteor.call way
Forget subscription and do it the old way. Send your query to an endpoint, in this case a Meteor method, and render the results. I prefer this method for one reason, $text. Minimongo does not support $text so you cannot use $text to search for stuff on the client. Instead you can set up your server's mongo with text indexes and meteor method to handle the search and render the results.
See what suits your priorities. The meteor.call way requires you to do a bit more work to make a "Search result" shareable through url but you get richer search results. The subscription way is easier to implement.
Here is a link to a search tutorial for meteor and read about $text if you are interested

Resources