React - Change URL for modal that can be open everywhere - javascript

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)
})

Related

Add query string to ALL links in application

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).

React Router Redirect component not giving the desired result

I am trying to redirect in react. But is not getting redirected to the desired place.
Here is the code:
<Redirect to={"https://www.google.com"} />
Now it is getting redirected to http://localhost:3000/https://www.google.com.
Could someone help me in this?
I would suggest to use instead <Link> component. That will generate for you an <a> tag with the required URL. <Redirect> component is for changing the route in application level.
<Link>: Provides declarative, accessible navigation around your application.
<Redirect>: Rendering a <Redirect> will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do.
Try as the following:
<Link to={'https://www.google.com'}>Go to Google</Link>
I hope this explains!
Seems like you are navigating away from your current website. In that case, you shouldn't be using <Redirect>. The <Redirect> component is meant to be used to redirect to another route within your app, not to an external website. The reason you get redirected to http://localhost:3000/https://www.google.com is because React Router treats the passed in to prop as a relative path, and appends it to the current host, which is http://localhost:3000.
If you want to do an external redirect, you don't need to use a <Redirect> component in this case, just use JavaScript:
window.location = 'https://www.google.com';
If you want to have a component that redirects when it mounts, you can use this component which contains a useEffect hook:
function ExternalRedirect({href}) {
React.useEffect(() => {
window.location = href;
});
return null;
}
// In your code:
<ExternalRedirect href="https://www.google.com" />

React Router v6.0.0-alpha.5 history prop removal - navigating outside of react context

According to the latest v6.0.0-alpha.5 release of react router, the history prop has been removed:
https://github.com/ReactTraining/react-router/releases/tag/v6.0.0-alpha.5
Removed the <Router history> prop and moved responsibility for setting
up/tearing down the listener (history.listen) into the wrapper
components (<BrowserRouter>, <HashRouter>, etc.). <Router> is now a
controlled component that just sets up context for the rest of the
app.
Navigating within the react context is simple with the useNavigate hook.
But, how does the removal of the history prop affect programmatically navigating outside of the react context?
For example, how would we keep our history in sync in order to navigate from inside redux, or an axios/http interceptor, etc., when we no longer can pass the history object?
Current V5 implementation:
https://reacttraining.com/react-router/web/api/Router
Or, from v6 onwards is the goal to rely on navigating from within react components only?
Thanks for the question, we know this is going to come up a lot. This is a common question we've gotten for years. Please be patient with us as we begin documenting all of these kinds of things, there's a lot to do!
Short answer: Typically people use thunks for async work that leads to wanting to navigate somewhere else (after a login, after a record is created, etc.). When your thunk is successful, change the state to something like "success" or "redirect" and then useEffect + navigate:
export function AuthForm() {
const auth = useAppSelector(selectAuth);
const dispatch = useAppDispatch();
const navigate = useNavigate();
useEffect(() => {
if (auth.status === "success") {
navigate("/dashboard", { replace: true });
}
}, [auth.status, navigate]);
return (
<div>
<button
disabled={auth.status === "loading"}
onClick={() => dispatch(login())}
>
{auth.status === "idle"
? "Sign in"
: auth.status === "loading"
? "Signing in..."
: null}
</button>
</div>
);
}
A bit more explanation:
For example, how would we keep our history in sync in order to navigate from inside redux
We've always considered this bad practice and reluctantly provided the history objects as first-class API to stop having philosophical conversations about app state and the URL 😅.
But today things are a bit different. The conversation isn't just philosophical anymore but has some concrete bugs when mixed with React's recent async rendering, streaming, and suspense features. To protect react router apps from synchronization bugs with the URL (that developers can't do anything about), v6 no longer exposes the history object.
Hopefully this explanation will help:
Changing the URL is a side-effect, not state. Thunks are used to perform side-effects that eventually figure out some state for the state container but aren't used for the side-effect in and of itself (at least that's my understanding).
For example, you may want to change the focus on the page after your redux state changes. You probably wouldn't try to synchronize and control the document's focus at all times through redux actions and state. Scroll position is the same. Ultimately the user is in control of these things: they can hit the tab key, click on something, or scroll around. Your app doesn't try to own or synchronize that state, it just changes it from time to time in response to actions and state that you do control.
The URL is the same. Users can type whatever they want into the address bar, click back, forward, or even click and hold the back button to go 3 entries back! It's the same kind of state as focus and scroll positions: owned by the user. The container can't ever truly own the URL state because it can't control the actions surrounding it. Mix in React's new and upcoming features and you're gonna lose that game.
In a nutshell: Change redux state > useEffect in the UI > navigate. Hope that helps!
I solved this for my login redirect by creating a navigate hook in my LoginForm UI component, then passing it to my login action creator, and calling it when the login endpoint returns successfully. In other words...
import React from 'react'
import {useNavigate} from 'react-router-dom'
function LoginForm (props) {
// create your navigate hook in your UI component
const navigate = useNavigate()
// other stuff...
handleLogin (loginFields) {
// then pass it into your action file, and call it
// when the query returns a successful result
dispatch(login(loginFields, navigate))
}
// other stuff, and return statement...
}

Refresh / Reload ember route from a component

I have a component, that's actually a modal dialog.
When I am done with that dialog and press the "Ok" button, I want to stay on the stay page from where I opened that dialog.
Which isn't difficult.
But the problem is that the dialog changes the data (I am getting data through a REST call) so I need to refresh the route that I already am on to reflect the data changes.
Since, I am calling it from a component, I don't have Route so can't call route.refresh().
I tried to get the router:
this.set('router', Ember.getOwner(this).lookup('router:main'));
and did transition to the same page:
_this.get('router').transitionTo('my-route')
But since the route hasn't changed (I only opened a dialog), transitionTo doesn't get triggered!
Is there a way I can force trigger transitionTo or refresh the page that I am on?
Thank you!
First, you can easily get the current route name by injecting the routing service to the component.
Then, you can get the current route instance and apply its refresh method:
// app/components/a-component.js
import Component from "ember-component";
import service from "ember-service/inject";
import getOwner from "ember-owner/get";
export default Component.extend({
routing: service("-routing"),
actions: {
refresh() {
const currentRouteName = this.get("routing.currentRouteName");
const currentRouteInstance = getOwner(this).lookup(`route:${currentRouteName}`);
currentRouteInstance.refresh();
}
}
});
For this, define refreshCurrentRoute method in nearest route or in application route file.
actions:{
refreshCurrentRoute(){
this.refresh();
}
}
From your component, you need to call refreshCurrentRoute action. either you can use ember-route-action-helper or by passing the closure action.

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