Reset react navigation stack history - react-navigation

Update
Changed to use DrawerNavigator as the root for now, but would still like to know if it's possible to use StackNavigator as root but behavior like tabs, or drawers.
Am using reactnavigation v5.
I have the following setup:
<RootStack.Navigator initialRouteName={'SplashNavigator'}>
<RootStack.Screen name={'SplashNavigator'} component={SplashStackNavigator} options={{headerShown: false}} />
<RootStack.Screen name={'DrawerNavigator'} component={DrawerNavigator} />
</RootStack.Navigator>
From SplashNavigator I do a navigation.navigate('DrawerNavigator', {screen:'Home'})
However, the header has a back button that navigates back to the splash screen.
Is there a way to reset the history so it'll take the DrawerNavigator as the main navigator?
Have tried StackActions.replace in HomeScreen but somehow it doesn't recognise the screen.
const HomeScreen = ({navigation}) => {
useEffect(() => {
navigation.dispatch(state => {
console.log(state);
return StackActions.replace('Home')
});
}, []);
...
ExceptionsManager.js:173 The action 'REPLACE' with payload {"name":"Home"} was not handled by any navigator.
Yet I do see the route in the state
"routeNames": [
"Home",
"Promotions"
],
Have tried CommonActions.reset() too but it didn't change anything.
const HomeScreen = ({navigation}) => {
useEffect(() => {
navigation.dispatch(state => {
console.log(state);
return CommonActions.reset({...state, key:null})
});

Related

Resetting navigation state after a deep link

After the app receives a deep link and navigates to it, the route (screen) that was specified as a deep link becomes the home screen! After receiving the deep link, each time the app is updated (and automatically re-loaded on the Android emulator), the app navigates to that deep link route (screen). How can I remove this route from the navigation state?
Demonstration of the Scenario:
adb shell am start -W -a android.intent.action.VIEW -d "casualjob://InvitedEmployee" com.casualjob
App is triggered by the command above and navigates to the route InvitedEmployee
User clicks on the Home screen link and navigates to it
I update the app's code
The app is automatically re-loaded to reflect the new code change
The app starts in InvitedEmployee, rather than the Home screen. I expect it to navigate to the Home screen!?
Deep Linking Configuration:
const config = {
screens: {
SingleStack: {
initialRouteName: "InitialScreen",
screens: {
EmployerActionVacancyScreen: "EmployerVacancyAction/:itemID/:opType/:itemStatus?",
ListShiftEmployeeInviteScreen: "InvitedEmployee",
InitialScreen: "*",
},
},
}
};
Stack Definition:
const SingleStack = () => {
const MyStack = createNativeStackNavigator();
return (
<MyStack.Navigator screenOptions={defaultScreenOptions}>
<MyStack.Screen name="InitialScreen" component={InitialScreen} options={{ title: "Home" }}/>
<MyStack.Screen name="ListShiftEmployeeInviteScreen" component={ListShiftEmployeeInviteScreen} options={{ title: "Shifts List", }}/>
</MyStack.Navigator>
);
};
I tried executing different pieces of code that I added to a useEffect hook in the route (screen) that the deep link leads to (InvitedEmployee in the example above). None of them seems to work!?
Solution 1 - throws an error:
The action 'RESET' with payload {"index":0,"routes":[{"name":"initialScreen"}]} was not handled by any navigator. This is a development-only warning and won't be shown in production.
const isFocused = useIsFocused();
useEffect( () => {
async function _fetchData() {
props.navigation.reset({
index: 0,
routes: [{ name: "initialScreen" }], // this is the home screen
});
}
if (isFocused) {
_fetchData();
}
}, [isFocused, ]);
solution 2: this does NOT seem to have any effect. As soon as the App is re-laoded after the code update, the deep-link's route appears back in the navigation state.
const isFocused = useIsFocused();
useEffect( () => {
async function _fetchData() {
props.navigation.dispatch(state => {
if (!state?.routes || state?.routes < 2) {
return;
}
const routes = state.routes.filter( (item, index) => {
if (item.name === "ListShiftEmployeeInviteScreen") { // This is the route (screen) that the deep link leads to
return false;
}
return true;
});
if (routes?.length > 0) {
return CommonActions.reset({
...state,
routes,
index: routes.length - 1,
});
}
return;
});
}
if (isFocused) {
_fetchData();
}
}, [isFocused, ]);

Cypress.Cookies.preserveOnce('session_id') isn't working when called in afterEach hook

I'm working with cypress tests and I want to avoid having to log in before each test. so, I wanted to preserve the cookies in each test file.
The log statement in the afterEach hook is triggered, however cookies are cleared in the second testcase.
describe('Users Page Scenarios', () => {
before(() => {
myApp.pages.Login.navigate();
myApp.pages.Login.login(
credentials.globalAdmin.email,
credentials.globalAdmin.password
);
});
beforeEach('navigate to users page before each test', () => {
myApp.sharedComponents.Header.navigateToUsers();
});
afterEach(() => {
Cypress.Cookies.preserveOnce('session_id');
cy.log('test');
});
describe('Users List', () => {
it('Should redirect the user to users page after clicking on users in the navigation header', () => {
cy.url().should('eq', `${Cypress.config().baseUrl}/user`);
});
})
describe('New User Creation', () => {
it('Should open new user modal after clicking on invite administrator', () => {
myApp.pages.Users.UsersList.inviteAdministrator();
cy.url().should('eq', `${Cypress.config().baseUrl}/user/new`);
});
it('Should create a new user successfully', () => {
myApp.pages.Users.UsersList.inviteAdministrator();
myApp.pages.Users.UsersInfo.createNewUser(user.generateUser());
})
});
The docs indicate that Cypress.Cookies.preserveOnce('session_id') is used in beforeEach().
Looks like after is too late.
describe('Dashboard', () => {
before(() => {
// log in only once before any of the tests run.
// your app will likely set some sort of session cookie.
// you'll need to know the name of the cookie(s), which you can find
// in your Resources -> Cookies panel in the Chrome Dev Tools.
cy.login()
})
beforeEach(() => {
// before each test, we can automatically preserve the
// 'session_id' and 'remember_token' cookies. this means they
// will not be cleared before the NEXT test starts.
//
// the name of your cookies will likely be different
// this is an example
Cypress.Cookies.preserveOnce('session_id', 'remember_token')
})
If you have localStorage or sessionStorage to preserve, or you have not identified all cookies correctly, try with cy.session()
beforeEach(() => { // must be beforeEach()
cy.session('mySession', () => { // preserves localStorage, sessionStorage, cookies
myApp.pages.Login.navigate();
myApp.pages.Login.login(...); // only called once (despite beforeEach())
})
})

How to add loader in vue js

How to add Loading effect in VUE js plus Laravel.
This is a single page website in vuejs, i want to add loader when i change the route.
Means when i click to another router, it takes time to fetch data and show meanwhile i want to show loader. Or When i submit a form i takes time for submit meanwhile i want to add loader.
Means when i click to another router, it takes time to fetch data and show meanwhile i want to show loader. Or When i submit a form i takes time for submit meanwhile i want to add loader.
Means when i click to another router, it takes time to fetch data and show meanwhile i want to show loader. Or When i submit a form i takes time for submit meanwhile i want to add loader.
Means when i click to another router, it takes time to fetch data and show meanwhile i want to show loader. Or When i submit a form i takes time for submit meanwhile i want to add loader.
Help please in VUE js + Laravel
add this line of code in your app.js file
router.beforeEach((to, from, next) => {
// add loader
next()
})
router.afterEach(() => {
// terminate you loader
})
so Full file is
window.Vue = require('vue');
import VueRouter from 'vue-router';
import VueProgressBar from 'vue-progressbar'
window.Fire = new Vue();
Vue.use(VueProgressBar, {
color: 'rgb(143, 255, 199)', //normal color for progress bar
failedColor: 'red', //color for failed progress bar
height: '2px'//height of progress bar can be changed here
})
Vue.component(HasError.name, HasError)
Vue.component(AlertError.name, AlertError)
Vue.use(VueRouter);
window.Fire = new Vue();
let routes = [
{
path: '/',
name: 'posts',
component: post,
},
{
path: '/general',
name: 'dashboard',
component: Dashboard,
},
];
let router = new VueRouter({
routes // short for `routes: routes`
});
router.beforeEach((to, from, next) => {
// add loader
VueProgressBar .start();
next()
})
router.afterEach(() => {
// terminate you loader
VueProgressBar.finish();
})
const app = new Vue({
el: '#app',
router,
data: {},
methods: {}
});
window.Fire = new Vue();
If you are requesting while browsing through the pages, the loader can work accordingly.
<script>
export default {
data: () => ({
loaderIsActive: false,
items: null,
}),
mounted() {
this.fetch();
},
methods: {
async fetch() {
this.loaderIsActive = true;
this.items = await axios.post('YOUR API');
this.loaderIsActive = false;
}
}
}
In this way you can use it.

React navigation Tab in Stack with button in Header

I'd like to have a TabNavigator embedded in a StackNavigator with a button in the Header used to navigate in the main Stack.
Here is a snack of my issue: https://snack.expo.io/#guigui64/tabs-in-stack
The propblem is when I create the TabNavigator:
const TabNavigator = createMaterialTopTabNavigator(
{
ScreenA,
ScreenB,
},
{
navigationOptions: {
headerTitle: 'Title when in tab',
headerRight: (
<Button
onPress={() => this.props.navigation.navigate('C')} // here is the issue !
title="ScreenC"
/>
),
},
}
);
I also tried creating a Component with static navigationOptions and have render() return a TabNavigator. In this case, the header appears fine but not the tabs.
Thanks in advance !

substate.get() is not a function using React Boilerplate

I have a component called Login, and these selectors:
const selectLogin = () => (state) => state.get('login');
const selectUser = () => createSelector(
selectLogin(),
(loginState) => loginState.get('user')
);
Here's what state looks like for the "login" component:
login: {
user: {
id: 206
}
}
In another component, I want to select the "user" object.
At the top of my file, I have
import { createStructuredSelector } from 'reselect';
import {
selectLogin,
selectUser
} from 'containers/Login/selectors';
const mapStateToProps = createStructuredSelector({
login: selectLogin(),
user: selectUser(),
});
When I use "selectUser()", I get "loginState.get is not a function".
If I remove all references to "selectUser()", I can access this.props.login.user. That works for me, but I want to know why I can't select from within the "login" state. The examples use the same "substate" convention in the selector, and they work. Any ideas?
Is this another component in another route?
You have to manually inject reducers and sagas required for the page in each route.
In route.js, loadReducer and inject it to the page, something like this:
{
path: '/projects/add',
...
getComponent(nextState, cb) {
const importModules = Promise.all([
System.import('containers/Project/reducer'),
System.import('containers/Login/reducer')
...
]);
const renderRoute = loadModule(cb);
importModules.then(([projectReducer, loginReducer ...]) => {
injectReducer('projects', projectReducer.default);
injectReducer('login', projectReducer.default);
renderRoute(component);
});
importModules.catch(errorLoading);
},

Resources