Add query string to ALL links in application - javascript

Here is the situation... I have a Next.js app that has been up for a bit, we have a ton of code already writen.
Recently we started running some ads and we need to understand how they are doing...
Someone could land on our site with either of the two URLs.
www.site.com/page // user came to our site NOT from ad
www.site.com/page?ad=campaign1 // user came from one of our ads.
If a user comes to our site with the "ad" querystring, I would like to append that to ALL links on our site.
How would I go about doing that in react/nextjs? we have a ton of components already built and even some blog posts where we are just rendoring raw HTML.
Without going and editing a zillion components. How would I go about appending the query string to all links?
Thanks

You could create a custom Link component, as a wrapper to next/link, that would check for the query string and add it to the href of the Next.js Link.
// components/link.jsx
import NextLink from 'next/link';
import { useRouter } from 'next/router';
const Link = ({ children, href }) => {
const router = useRouter();
const [, queryString] = router.asPath.split('?');
const hrefWithQuery = `${href}${queryString ? `?${queryString}` : ''}`;
return <NextLink href={hrefWithQuery}>{children}</NextLink>;
};
export default Link;
Then replace all imports of next/link with the path to the new component wherever they are used (a simple search & replace would do).

Related

Nextjs - first level dynamic route

I want to have user profiles in my app at domain.com/:username .How do I do it? creating a new folder in /pages will create a new URL section like /user/:username which I don't want.
Just name your file inside pages as [username].js
Creating a dynamic route
You can create a dynamic route by putting the filename in brackets. For instance:
pages/[id].js
pages/[slug].js
pages/posts/[slug].js
pages/[author]/[slug].js
pages/[author]/bio.js
Notice how the dynamic route can be at any level. It doesn't simply need to be at the root of the pages folder, and it doesn't need to be the last level of the url either. Also notice that you can name the dynamic route anything you want. You're not restricted to just using [id] or [slug].
In your case, use pages/[username].js
Accessing the route name
If you create a dynamic route at pages/posts/[slug].js, any page at https://example.com/posts/slug-of-the-post will lead to that page. However, you likely want different content on each page (i.e., that the user is on https://example.com/posts/slug-of-the-post, not https://example.com/posts/slug-of-a-different-post. For this, you need to access the contents of the route.
Inside the page
You can use the router to get the name of the route.
// pages/posts/[slug].js
import { router } from 'next/router'
export default function PostPage() {
const router = useRouter()
const slug = router.query.slug // "slug" because that was the name of the file
return <>{/* page contents */} </>
}
So on page https://example.com/posts/slug-of-the-post, the variable slug will be slug-of-the-post.
If you used [id].js, use router.query.id instead.
GetStaticProps/GetServerSideProps
Using the server-side functions, the process is very similar.
// pages/posts/[slug].js
// bottom of the file
export async function getServerSideProps(context) {
const slug = context.params.slug
return {
props: {},
}
}
Docs
By the way, I'd also recommend checking out the docs if you haven't already:
https://nextjs.org/docs/routing/dynamic-routes

Keep param consistent on location change ReactJs

I am using react router v4 to change location in ReactJs.
this.props.history.push("/profile");
<Link to="/profile" />
The above code works fine.
Now I want to keep a param consistent in URL http://localhost:3000?source=test by using the same code as above.
One approach is that I find all the occurrences in the code and add condition that if params source=test exist then append it to the the URL as well but this approach doesn't look fine to me as I have add condition on every redirect, Link and history.push
Second approach that I find is that use of listener on location update given by react router
In my Main Route file
class App extends Component {
componentDidMount() {
this.unlisten = this.props.history.listen((location, action) => {
if (/source=ep/.test(this.props.location.search)) {
location.search = _startsWith(location.search, "?") ? location.search + "&source=test" : "?source=test"
}
});
}
}
With this approach I can easily append the params in search query of react router but the param doesn't show up in URL.
the URL looks like this http://localhost:3000/profile and When I get search params from react-router console.log(this.props.location.search) it shows the param source=test and it's exactly what I want but In this case if user refreshes on this page the search params lost from react-router as well because it's not in the URL.
Can you guys help me to keep source=test consistent even in URL.

Vue.JS - Both 'history' and 'abstract' router?

I am creating a VueJS app in which the user fills out a 5-step form.
These steps are routed to /step-1 through /step-5 in the Vue Router. However, I would like the site to return to the index page (/) when refreshing the page.
I could use abstract mode for this – but the result page is generated from the following url: /result/:userid in which I need the state to be history in order to be able to get the userid from the URL (and then do a post request to the server).
I also want this URL to be accessible even after finishing the form, so abstract here is not an option unfortunately.
So – is it possible to use both modes? Refresh the page to index.html when refreshing the form-pages, but then use history mode to render the result?
You cannot do this. It is either history or abstract but not both. Having said this, there are a couple of things you can do.
Approach 1: Use history mode with steps as query params
So instead of having routes like /step-1 or /step-2, use then as part of query params. So you will have routes like:
Index route: example.com/?step=1, example.com/?step=2
Result route: example.com/result/:userId
Approach 2: Use abstract mode with higher order component
Here, you will have a router with abstract but it will only serve as a state router and won't help with any browser URL manipulation.
Build a higher order component like AppComponent where you will have your own regular expressions to determine the route. It would look like:
// Should match route /result/:userId
const IS_RESULT = new RegExp('/result/(\\d+)$');
// User RegExp groups
const IS_STEP = new RegExp('/step-(\\d+)$');
export default class AppComponent extends Vue {
// Use Vue.js created hook
created() {
const path = window.location.pathname;
// Top level routing of the application
if (IS_STEP.test(path)) {
// Do something. You are in step-1/step-2/etc.
} if (IS_RESULT.test(path)) {
// Do something. You are in /result/:userId
// Get userId
const groups = IS_RESULT.exec(path);
const userId = groups[1];
} else {
// Goto Error page
throw new Error('Unknown route');
}
}
}
Approach 3: Use Multi-page SPA
Here, you will create two single page application. The first app will have routes /step-1, /step-2, etc. You will use abstract mode for this. The second application will have /result/:userId route with history mode.
In this architecture, when a user is on step-5, instead of pushing a new state to the router, you will use HTML5 history API to change the router and then cause a forced page refresh. Also, there are other ways you achieve this.
You can simply have a redirect in native javascript where you call it window.location.href('yourHomePage.com') and it will do a full refresh.

React - Change URL for modal that can be open everywhere

I'm new in React and I was asked to implement this feature in an App mostly done. So, I don't want to destroy everything.
I have a modal containing components login/register/activation/password-recovery/password-reset according the situation. This modal can appear on every single public page. It's possible to navigate in the modal from login to register, from login to password-recovery, from password-reset to login.
We can access to the modal from a link in he header and from other links through the site. The modal appears with an animated transition.
I was asked to change the URL according to the modal content displayed.
The URLs must be:
site.com/en/login
site.com/en/register
site.com/en/activation
site.com/en/password-recovery
site.com/en/password-reset
The page behind the modal should remains even if the URL was site.com/en/page1/info1/[...] or the homepage should be displayed by default behind the modal on direct URL access/refresh.
I found many pieces for this puzzle on the web, but pieces don't seem to fit together. I just want to know the best way to achieve this task.
I don't have convincing code to show right now.
If that can help, it's a React-Redux App using JSX on NodeJS server.
if your component is rendered via Router you can use history.push(), else you can wrap your component with withRouter from react-router-dom and then use history.push(),
import { withRouter } from 'react-router'
const myComponent = () => {
...
}
// by this history is going to be available from props in this component
export default withROuter(myComponent)
if neither of then was not working , you still have location object from window of browser left , try that....
Maybe the 'history' library can help you easily
https://www.npmjs.com/package/history
import createHistory from 'history/createBrowserHistory'
const history = createHistory()
history.listen((location, action) => {
// location is an object like window.location
console.log(action, location.pathname, location.state)
})

How to use js code to forward reactjs-router?

when u seem to require forward in reactjs we used to put a Link or button ,and then consumer click it ,then the page reload corresponding path of router . Now,I want the page turn to other path of router when I request a post and the status of response is 200. It can't use a link or button ,could reactjs use code to do this? like : CertainComponent.setPath(otherPath); CertainComponent.turn;
My English is poor , it may be not clear to delive the function which i want to do.
Thanks!
I think you want to use this.context.router.push('/users/12')
https://github.com/reactjs/react-router/blob/master/docs/API.md#routercontext
First of all the component you are using has to be a container, which means you have to create it with connect() so it has access on store and dispatch:
let MyComponent = ({ dispatch, store }) => {
store.routing.push('url');
}
export default connect()(MyComponent)
And this depends how you named the router key on your store when you combined the routing reducer from redux-router on your store.
There is also another alternative, where you could do
import { hashHistory } from 'react-router';
hashHistory.push('next-url');

Categories

Resources