I am working on a website and there for using Svelte and the svelte-routing library .
The svelte-routing library has a method called navigate(path).
I use this function on a click of a button and it works perfectly. But in my routeHandling.js file its not working as expected.
I can see that it sets the url in the browser but its staying on the same page, so I have to press F5 (reload the page) to load the page.
import {navigate} from "svelte-routing";
import * as axios from "axios";
export function checkLoggedIn() {
console.log("checkLoggedIn is now getting executed");
if (window.location.pathname !== "/" && window.location.pathname !== "/registration") {
axios.default.get('http://127.0.0.1:5000/user', {
headers: {
'Authorization': `${localStorage.getItem("token")}`
}
}).catch(response => {
navigate("/");
});
}
}
Thanks in advance!
you need to use the navigate method inside a svelte component. Try creating a method that calls the checkLogggedIn() method from your svelte component and does navigate() on successful return.
import checkLoggedIn from "./router";
import {navigate} from "svelte-routing";
const checkUser = async () => {
let res = await checkLoggedIn();
if (res.status === 200) {
navigate('/')
} else {
navigate('/login')
}
}
something like this should work. you'll want to wait for the response before navigating so I made it an async function
Another thing you will want to check is if you're using the -s or -single flag when you start svelte. Check your NPM scripts.
Just in case you're new to svelte-routing:
you need to add a Router to your App, and create paths with the componenets to be rendered on them. like this
<Router>
<Route path="home">
<Home />
</Route>
<Route path="about">
<About />
<Route />
</Router>
where the <Home /> and <About /> are components you would like to render on those routes.
You can use location.replace("/")to reload and get all the components.
But you are removing the history for the first page so you can't go back.
const checkUser = async () => {
let res = await checkLoggedIn();
if (res.status === 200) {
location.replace("/");
} else {
navigate('/login')
}
}
or you could do a location.reload(); after navigate to keep the history
if (res.status === 200) {
navigate('/')
location.reload();
} else {
navigate('/login')
}
}
I have some dynamically created Links and Routes (React Router) with path be like /details/{id} (using useParams)
When I click that link from '/' path everything works ok, but when I click it from another dynamically generated route (/details/{id}), it's just updating URL (specifically ID}, not the page's content
If I set force refresh prop on the BrowserRouter or just manually refresh the page, everything begins to work ok, but I don't want to refresh the whole page every time.
const App = () => {
return(
<BrowserRouter>
<div>
<Route path='/' exact>
<FirstComponent id={id}/>
</Route>
<Route path={`/details/:id`}>
<SecondComponent anotherId={anotherId}/>
</Route>
</div>
</BrowserRouter>
)
}
const FirstComponent = ({id}) => {
return <Link to=`/details/${id}`></Link> //renders SecondComponent
}
const SecondComponent = ({anotherId}) => {
const {id} = useParams()
//does something with id
return <Link to=`/details/${anotherId}`></Link> //Should render SecondComponent with another id but it doesn't
}
I am using the 'react-places-autocomplete' library. I understand that I have to load the API using my key. I can't figure out where to place the script for the key such that the program will work.
I saw a StackOverflow page where someone said to load it statically in index.js, which I tried:
import 'react-places-autocomplete';
...
ReactDOM.render(
<div>
<BrowserRouter>
<App />
</BrowserRouter>
<script src="https://maps.googleapis.com/maps/api/js?
key=MY_KEY&libraries=places"></script>
</div>
, document.getElementById('root'));
This doesn't work, I also tried to load it directly in the component (Which doesn't seem correct):
class My_Component extends React.Component {
...
render() {
return (
<div>
<script src="https://maps.googleapis.com/maps/api/js?
key=MY_KEY&libraries=places"></script>
<PlacesAutocomplete
value={this.state.address}
onChange={this.handleChange}
onSelect={this.handleSelect}
>
....
</div>
);
}
}
Using these approaches I keep getting the "Google Maps JavaScript API library must be loaded" error, and I have looked at the documentation and it doesn't specify where the tag needs to be placed, just that it needs to be somewhere.
I have used it this way in one of my project
class PlacesAutocomplete1 extends React.Component {
constructor(props) {
super(props);
this.state = {
googleMapsReady: false,
};
}
componentDidMount() {
script is loaded here and state is set to true after loading
this.loadGoogleMaps(() => {
// Work to do after the library loads.
this.setState({ googleMapsReady: true });
});
}
componentWillUnmount() {
// unload script when needed to avoid multiple google scripts loaded warning
this.unloadGoogleMaps();
}
loadGoogleMaps = callback => {
const existingScript = document.getElementById("googlePlacesScript");
if (!existingScript) {
const script = document.createElement("script");
script.src =
"https://maps.googleapis.com/maps/api/js?key=YOUR_KEY&libraries=places";
script.id = "googleMaps";
document.body.appendChild(script);
//action to do after a script is loaded in our case setState
script.onload = () => {
if (callback) callback();
};
}
if (existingScript && callback) callback();
};
unloadGoogleMaps = () => {
let googlePlacesScript = document.getElementById("googlePlacesScript");
if (googlePlacesScript) {
googlePlacesScript.remove();
}
};
render() {
if (!this.state.googleMapsReady) {
return <p>Loading</p>;
}
return (
// do something you needed when script is loaded
}
I have a script that loads an iframe that i have to embed on a particular route
My application is a universally rendered React app, and I included the script in my JSX code in the component registered to my route.
The iframe loads when I refresh the page on the route, but when I go from home -> other route, it wont load.
I've tried different workarounds using componentWillMount and componentDidMount, but to no avail. Is there a way to force it to load when I visit the route from another route?
EDIT: i've checked and the script, is always there, but does not execute when not using server-side rendering
someone else had the same problem here and there was no sufficient solution short of including it at the root component of the app, which is overkill. so i have no idea what the solution is :(
class Component extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div className='container'>
<script id="twine-script" src="//apps.twinesocial.com/embed?app=WCD&showNav=yes"></script>
</div>
}
You should be able to inject a script on componentWillMount into the document head. You can argue that this isn't the most React way, but I think in this particular case it makes sense.
const MyRouteComponent = React.createClass({
componentWillMount() {
const script = document.createElement('script');
script.type = 'text/javascript';
script.onload = () => {
this.setState({
isLoaded: true
});
console.log(TwineSDK); // TwineSDK should be defined now
};
script.src = '//apps.twinesocial.com/embed?app=WCD&showNav=yes';
document.head.appendChild(script);
},
getInitialState() {
return {
isLoaded: false
}
},
render() {
return (
<div>
{
this.state.isLoaded ? <div>Loaded!</div> : <div>Loading...</div>
}
</div>
);
}
});
I am using react-router 2. My routes are defined as
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="/about" component={About}/>
<Route path="/login" component={Login} onEnter={redirectToDashboard}/>
<Route path="/logout" component={Logout} onEnter={logoutSession}/>
<Route path="/dashboard" component={Dashboard} onEnter={redirectToLogin}/>
</Route>
Everything working fine but I am having problem disabling back button from my dashboard page.
After successful login I am redirecting user to dashboard page but when user clicks back button it goes to login page again. I want to disable back button of browser when user is on dashboard page.
Your best bet, is when the user is login he/ she is redirected to dashbaord. if for some reason the user click on back button you should:
if the user is logged in
stay on the page dashboard
if(logged) {
history.pushState(null, null, location.href);
window.onpopstate = function(event) {
history.go(1);
};
}
it will be not possible to go back.
Applying all these hacks the URL changes to login for a moment and then to wherever-we-push.
Instead, what we can do is: In login, where api endpoint returns success, do:
history.replace('/Whatever_screen')
This will remove login screen from window.history stack, and the screen will not flicker.
On your page which you want to disable back (example, on LoginApp ) add this block, to disable web history back
componentDidMount() {
window.history.pushState(null, document.title, window.location.href);
window.addEventListener('popstate', function (event){
window.history.pushState(null, document.title, window.location.href);
});
}
it's not possible to disable browser buttons.
my advice is to redirect user back to dashboard page if he/she is logged
Actually you can't disable back button. You can use a hack by preventing browser's "back" action. Just add to your Dashboard component compnentWillMount() lifecycle method some code that will trigger browser's "forward" action:
componentWillMount() {
setTimeout(() => {
window.history.forward()
}, 0)
window.onunload=function(){null};
}
But most probably a better solution would be some redirection based on users logged state.
in your login screen add replace to /dashboard
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom'
import createBrowserHistory from 'history/createBrowserHistory'
const history = createBrowserHistory()
class LoginPage extends Component {
componentDidMount(){
history.replace({ pathname: '/dashboard' })
}
render() {
const { history } = this.props
return (
<div>
<h1>Login Page</h1>
<button onClick={() => {
login().then(() => {
history.push('/dashboard')
})
}}>Login</button>
</div>
);
}
}
export default withRouter(LoginPage);
The reason is replace your current path (/login) to /dashboard. Before adding this, please make sure you setup your authentication correctly.
In order to improve the code reusability, we can add an event listener in our index.html and dispatch the browser back disable event from all of our componentDidMount() methods.
In the index.html,
window.addEventListener('navigationhandler', function (e) {
window.history.pushState(null, document.title, window.location.href);
window.addEventListener('popstate', function (event) {
window.history.pushState(null, document.title, window.location.href);
});
});
In React componentDidMount() method,
componentDidMount() {
window.dispatchEvent(new CustomEvent("navigationhandler"));
}
It's not possible to disable browser buttons. But we can use history methods like listen(), go() and push() to override the default behaviour of back button in react.js. Also try to use withRouter().
The following is the sample code for doing this. Please look into componentDidMount() and componenetDidUnmount() methods.
import React from "react";
import { Redirect, Switch, Route, withRouter } from "react-router";
import Page1 from "./Page1";
import Page2 from "./Page2";
import Page3 from "./Page3";
class App extends React.Component {
constructor(props) {
super(props);
// Store the previous pathname and search strings
this.currentPathname = null;
this.currentSearch = null;
}
componentDidMount() {
const { history } = this.props;
history.listen((newLocation, action) => {
if (action === "PUSH") {
if (
newLocation.pathname !== this.currentPathname ||
newLocation.search !== this.currentSearch
) {
this.currentPathname = newLocation.pathname;
this.currentSearch = newLocation.search;
history.push({
pathname: newLocation.pathname,
search: newLocation.search
});
}
} else {
history.go(1);
}
});
}
componentWillUnmount() {
window.onpopstate = null;
}
render() {
return (
<Switch>
<Route exact path="/" render={() => <Redirect to="/page1" />} />
<Route path="/page1" component={Page1} />
<Route path="/page2" component={Page2} />
<Route path="/page3" component={Page3} />
</Switch>
);
}
}
export default withRouter(App);
For more: Disable react back button
Simple and Sweet.
No need to mess with history stack.
solution even does not depend on react router.
It will even prevent the current component from unmounting when back button is clicked, hence it also preserves state of the app as well.
// prevent back
useEffect(() => {
window.addEventListener('popstate', (e) => {
window.history.go(1);
});
}, []);