Is there a way to prevent back navigation using react's useNavigate hook? I'm currently using navigate("/",{replace: true}) for the time being but would like to have a proper solution for it.
The only way to fight browser's own mechanism like History and navigation is to check history.length:
useEffect(() => {
if (global.history.length> 1) {
window.open(window.location.href, "_blank");
}
}, []);
Imo it's rather confusing. Also when user opens new tab, history.length becomes 1. So code above will not bring another tab only if opened from bookmark/by clicking link with target="_blank".
Related
DESCRIPTION
I have an app that should trigger an analytics event just once at a specific screen when a component is shown to the user.
i.e: if the user open the application and land to home screen and the component is showing, then the analytics event should be sent. If the user navigate to Settings screen and the component is there, then the event should trigger, but if the user navigate back to home screen, the event shouldn't trigger. Just have to be called once per screen.
If the user quit the app completely, the event should fire again once reopen it
STACK
react-native
react-navigation
react-redux
WHAT I'VE DONE
I've tried to use the useIsFocused hook with useEffectand useRef but it turns that when the screen is rerender for an async fetch event, the state inside my useEffect is reset and the analytics event trigger again, which is not the expected behavior.
const isHasBeenFocused = useRef()
const isFocused = useIsFocused()
useEffect(()=>{
if(isHasBeenFocused.current){
return;
}
isFocused && dispatch(analyticsEvent, payload)
isHasBeenFocused.current = isFocused
}, [])
This is my approach, but I don't know if it's the correct one or if there's another, better option.
Hope anyone could help me on this.
If you want the analytics event to fire only once for the lifetime of the app installation, you could use AsyncStorage for flags like this. AsyncStorage used to be a core RN module but is now community-based.
This will persist until the app is uninstalled.
useEffect(() => {
const check = async () => {
const hasReported = await AsyncStorage.getItem('yourKey');
if (hasReported) return;
AsyncStorage.setItem('yourKey', true);
dispatch(analyticsEvent, payload);
};
check();
}, []);
If you want the analytics to fire once per session, you could use the same solution with an AppState listener to reset the value to something falsy when the app is backgrounded. There's a good example of using AppState in the React Native docs.
If you need the value to persist across app installs, the best solution is to store it in your backend.
Using NextJS and Redux.
Let me briefly explain as it seems complicated without understanding the website mechanic.
My Website Buttons:
Home (Goes to homepage)
Search (Opens search menu in homepage)
Sign In (Goes to sign in page)
Imagine having 3 buttons in the navigation bar. First button goes to '/' page. Second button's function is to open up a sliding menu that is only available in page '/'. Third button takes you to '/sign-in' page. Remember the second button. So if the second button is clicked when the website is on '/' page, there is no problem with the sliding menu opening and closing. But, if lets say I am in '/sign-in' page and clicked on the sliding menu opening button, I want my website to first go to '/' page, then open up the sliding menu.
Snippet goes to the '/' page but fails to execute the next line of code.
const searchClickHandler = useCallback(() => {
if (window.location.pathname !== '/') {
router.push('/');
}
dispatch(toggleFilterMenu());
}, [dispatch, router]);
I tried using Thunk principle inside Redux but as you may know useRouter hook cannot be used inside a Redux file. I tried async await keywords but dispatch method gives warning saying that I cannot use await for dispatch method.
Any help would be appreciated.
You could pass some "state" in the PUSH to the "/" route and check this in the receiving component. In other words, effect a navigation to the "/" route first, and then in that component check if the search menu should be opened.
Example:
const searchClickHandler = useCallback(() => {
router.push(
{
pathname: "/",
query: { openMenu: true }
},
"/"
);
}, [dispatch, router]);
const router = useRouter();
useEffect(() => {
if (router.query.openMenu) {
dispatch(toggleFilterMenu());
}
}, [router]);
If I am understanding correctly. Then, You can use the useEffect. Hook to trigger the function that opens the sliding menu after the component has finished rendering.
import { useEffect } from 'react';
const searchClickHandler = useCallback(() => {
dispatch(toggleFilterMenu());
}, [dispatch]);
useEffect(() => {
if (window.location.path !== '/') {
router.push('/');
}
searchClickHandler();
}, [searchClickHandler, router]);
When the button is clicked, hook will be triggered and will check the and the current path, and then it's open the menu.
OK actually, I found out that both answers and my method actually works. Problem was with another action called resetSlidingMenuStates intercepts with what I want to accomplish in every new page reload... I spent 2 hours on this but now while tinkering, found out it was because of another action I put.
We can lock the this thread. Thanks.
I am new to React, Redux and Typescript. I am trying to implement SSO and OAuth like described here. I was able to do it with a login button, so after clicking, it redirects to my app (if parameters are correct). However, I would like to have the process starting automatically while opening a page. (without any additional button). I assume that I can use useEffect. This is my code, but it creates an infinite loop.
What would be the proper way of removing infinite loop here?
export function Auth() {
useEffect(() => {
window.open(getAuthorizeHref(), "_self");
}, []);
return <div />;
}
I'm working on an app with React Native and React Navigation. For most of the app, I have a bottom tab navigator and header. However, in one section of the app, the user can make a call and is taken to a screen with no navigation. The user shouldn't be able to navigate to the previous screen without ending the call. How can I prevent the user from going back?
if you use react-native-navigation v5, it supports several listeners and the one you need is beforeRemove this is being called before the screen gets removed and you can prevent it's default behaviour conditionally.
useEffect(() => {
navigation.addListener("beforeRemove", (e) => {
if(yourCondition) {
return ;
} else {
e.preventDefault();
}
});
}, [navigation]);
I'm writing a react app which uses react-router-dom for routing. For one of the routes I have to perform an action when the user leaves (perform api request & stop the timer).
I can do this either
In the cleanup function returned by useEffect hook inside the component rendered for that route
or
Attach to the router and detect the route changes.
Which way is better? Or perhaps there's some other way?
You can use componentWillUnmount. However, useEffect works just as well!
That is likely the better way to handle this event.
I will try to use react router tools to make effects when your are navigating.
Unmount is kind of side effect of navigation, but maybe could not unmount, or you can unmount that component for other reasons.
if you are using hooks maybe you can use useLocation and store what is the current page and do something like this:
function usePageViewTracker() {
const location = useLocation()
[lastLocation, setLastLocation] = useState('')
useEffect(() => {
if (lastLocation === 'specialLocation') {
// call your API
}
setLastLocation(location)
}, [location])
}