I want to import screen to my react navigation but when i import class React.Component its unidentified
my routes.js
import * as Screens from '../screens/index';
import {FontIcons} from '../assets/icons';
export const MainRoutes = [
{
id: 'LoginMenu',
title: 'Marketing',
icon: FontIcons.login,
screen: Screens.GridV1,
children: [
{
id: 'Login1',
title: 'Login V1',
screen: Screens.GridV1,
children: []
},
{
id: 'Login2',
title: 'Login V2',
screen: 'GridV2',
children: []
},
{
id: 'SignUp',
title: 'Sign Up',
screen: 'GridV2',
children: []
},
{
id: 'password',
title: 'Password Recovery',
screen: 'GridV2',
children: []
},
]
}
];
My screens/index.js
export * from './navigation';
export * from './dash';
When i check the Screens import with
console.log(Screens);
Everythings is well. But when i execute
console.log(Screens.GridV1);
i cant reach the GridV1 class
Please help me to solve my problem here. Thanks you
From your chrome snapshot of Screens, it shows that at that moment you console.log, Screens object only contains one element {__esModule: true}. GridV1, GridV2 and all other modules were resolved late with a delay.
Therefore you should see it works with setTimeout, ex:
setTimeout( () => console.log(Screens.GridV1), 100 );
But the real problem still hides behind. Normally import javascript module won't have such side effect, it should have works as you expected. Check if there are any special initialization mechanism of those modules.
Related
I used setDefaultOptions in react-native-navigation to set a global topbar button on the right side using rightButtons property.
But on some screens, I want to override that global button and set a new button. So I used mergeOptions method inside the component that I want the new button on the topbar.
It works only on iOS but on android. I tried different ways to fix this issue. But couldn't find any solution.
To demonstrate let's imagine the global button is Notification. Also let's imaging I'm gonna use that in many screens except Profile Screen. Please check the below images.
The first two images are from android. Third one is from iOS. You can see on android Profile Screen has notification button on the topbar. It should be Edit button just like in iOS.
Image: 1
Android: 1
Image: 2
Android: 2
Image: 3
iOS: 1
Here is my code.
index.js
import { Navigation } from "react-native-navigation";
import App from './App';
import Notification from "./src/components/Notification";
import Profile from "./src/screens/Profile";
const defaultNavigationOptions = {
topBar: {
rightButtons: [{
id: 'com.myApp.Notification',
component: {
id: 'com.myApp.Notification',
name: 'com.myApp.Notification'
}
}],
}
}
Navigation.registerComponent('com.myApp.WelcomeScreen', () => App);
Navigation.registerComponent('com.myApp.Profile', () => Profile);
Navigation.registerComponent('com.myApp.Notification', () => Notification);
Navigation.events().registerAppLaunchedListener(() => {
Navigation.setDefaultOptions(defaultNavigationOptions);
Navigation.setRoot({
root: {
bottomTabs: {
children: [
{
stack: {
id: 'HOME_TAB',
children: [{
component: {
id: 'com.myApp.WelcomeScreen',
name: 'com.myApp.WelcomeScreen',
},
}],
options: {
bottomTab: {
text: 'Home'
}
}
}
},
{
stack: {
id: 'PROFILE_TAB',
children: [{
component: {
id: 'com.myApp.Profile',
name: 'com.myApp.Profile',
},
}],
options: {
bottomTab: {
text: 'Profile'
}
}
}
}
]
}
}
})
});
Profile.js
import { StyleSheet, Text, View } from 'react-native'
import React, { useEffect } from 'react'
import { Navigation } from 'react-native-navigation'
const Profile = (props) => {
useEffect(() => {
Navigation.mergeOptions(props.componentId, {
topBar: {
rightButtons: [{
id: 'edit',
text: 'Edit'
}]
}
})
}, [])
return (
<View>
<Text>Profile</Text>
</View>
)
}
const styles = StyleSheet.create({})
export default Profile;
I tried Profile.options = {} method as well. But no luck.
I'm using:
react-native-navigation: 7.28.1
react-native: 0.64.2
I've just finished building an Expo app along with TypeScript. Everything seems to be okay in the live testing mode, but, after compiling the app into a standalone app (for Android at least, haven't tried for ios), the navigation between the screens seems to be broken. I cannot even go past the first screen (when I press on the next button, the app just crashes immediately), although I know all screens are doing just fine in isolation. I am using Expo version 4.4.1, under the managed workflow.
This is my NavigationStack.tsx:
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import EntireMapScreen from '../app/screens/EntireMapScreen';
import CardFormScreen from '../app/screens/CardFormScreen';
import ChooseOfferScreen from '../app/screens/ChooseOfferScreen';
import DecisionScreen from '../app/screens/DecisionScreen';
const screens = {
Decision: {
screen: DecisionScreen
},
ChooseOffer: {
screen: ChooseOfferScreen
},
Payment: {
screen: CardFormScreen
},
EntireMap: {
screen: EntireMapScreen
}
}
const navigationStack = createStackNavigator(screens, {
defaultNavigationOptions: {
headerShown: false
}
});
export default createAppContainer(navigationStack);
The way one file generally looks like is this (DecisionScreen.tsx):
import React from "react";
import { NavigationStackProp, NavigationStackScreenProps } from "react-navigation-stack";
import AsyncStorage from '#react-native-async-storage/async-storage';
import { NavigationInjectedProps, withNavigation } from "react-navigation";
/**
* An extremly simple non-GUI screen, which decides if the user should pay again for the app
* or if the app can simply be used.
*/
class DecisionScreen extends React.Component<NavigationInjectedProps, {
form: {
status: {
cvc: string,
expiry: string,
name: string,
number: string
},
valid: boolean,
values: {
cvc: string,
expiry: string,
name: string,
number: string,
type: string
}
},
fontsLoaded: boolean,
waitingServerResponse: boolean,
showError: boolean // if true, we know something went wrong billing the user with
// the currently inserted details
}> {
keyboardDidHideListener: any;
constructor(props: any) {
super(props);
this.state = {
form: {
status: {
cvc: "incomplete",
expiry: "incomplete",
name: "incomplete",
number: "incomplete"
},
valid: false,
values: {
cvc: "",
expiry: "",
name: "",
number: "",
type: ""
}
},
fontsLoaded: false,
waitingServerResponse: false,
showError: false
};
}
makeDecision = async (trial: number) => {
...
}
render = () => <></>;
componentDidMount = () => {
this.makeDecision(1);
}
}
export default withNavigation(DecisionScreen);
I've lost the last 6 hours or so in finding a similar situation on the internet. The best I could find was this article: https://dev.to/andreasbergqvist/react-navigation-with-typescript-29ka, which did not solve the issue. Does anybody know how I could be solving this issue?
The problem was finally due to the fact there was a promise in an async function which did not resolve until the moment of being called later on as an undefined. Therefore, the solution was to simply add an await statement next to that promise.
The error appears when I use a v-for loop to go through the 'allPosts' data on my div.
The Nuxt documentation says 'Modules: every .js file inside the store directory is transformed as a namespaced module'. Maybe I'm missing something in this regard?
pages/index.vue
<template>
<section id="postgrid">
<div v-for="post in allPosts" :key="post.id"></div>
</section>
</template>
<script>
import {mapGetters} from 'vuex'
import PostTile from '#/components/Blog/PostTile'
export default {
components: {
PostTile
},
computed: mapGetters(['allPosts'])
}
</script>
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import Posts from './posts'
const store = new Vuex.Store({
modules: {
Posts
}
})
store/posts.js
const state = () => ({
posts: [
{
id: 0,
title: 'A new beginning',
previewText: 'This will be awesome don\'t miss it',
category: 'Food',
featured_image: 'http://getwallpapers.com/wallpaper/full/6/9/8/668959.jpg',
slug: 'a-new-beginning',
post_body: '<p>Post body here</p>',
next_post_slug: 'a-second-beginning'
},
{
id: 1,
title: 'A second beginning',
previewText: 'This will be awesome don\'t miss it',
category: 'Venues',
featured_image: 'https://images.wallpaperscraft.com/image/beautiful_scenery_mountains_lake_nature_93318_1920x1080.jpg',
slug: 'a-second-beginning',
post_body: '<p>Post body here</p>',
prev_post_slug: 'a-new-beginning',
next_post_slug: 'a-third-beginning'
},
{
id: 2,
title: 'A third beginning',
previewText: 'This will be awesome don\'t miss it',
category: 'Experiences',
featured_image: 'http://eskipaper.com/images/beautiful-reflective-wallpaper-1.jpg',
slug: 'a-third-beginning',
post_body: '<p>Post body here</p>',
prev_post_slug: 'a-second-beginning',
next_post_slug: 'a-forth-beginning'
}
]
})
const getters = {
allPosts: (state) => state.posts
}
export default {
state,
getters
}
You have a number of issues in how you are setting up and accessing your store. Firstly you are creating your store using the "classic mode" which the docs tell us:
This feature is deprecated and will be removed in Nuxt 3.
So in order to be using the latest methods your store/index.js should look like this:
//store/index.js
//end
This is not a mistake, you don't actually need anything in it, just have it exist. There is no need to import vue or vuex or any modules.
Your store/posts.js can largely stay as it is, just change your state, mutations, getters, and actions to be exported constants and delete the bottom export:
//store/posts.js
export const state = () => ({
posts: [
...
]
})
export const mutations = {
}
export const actions = {
}
export const getters = {
allPosts: state => state.posts
}
//delete the following
export default {
state,
getters
}
Secondly you seem to be using mapGetters incorrectly. If you set up your store like I have above, you can use it in pages/index.vue like so:
//pages.index.vue
<script>
import {mapGetters} from 'vuex'
export default {
computed: {
...mapGetters ({
allposts: 'posts/allPosts'
})
}
}
</script>
Then you can access "allPosts" in your template as you would any computed property or access it with "this.allPosts" in your script.
I've read countless react-navigation docs, and I know there is way to do this, but it's definitely what I would call non-trivial and definitely non-intuitive.
I have a root navigation stack:
export const NavigationStack = StackNavigator({
Splash: {
screen: Splash
},
Signup: {
screen: Signup
},
Login: {
screen: SignIn
},
ForgottenPassword: {
screen: ForgottenPassword
},
Discover: {
screen: Discover
},
ProfileShow: {
screen: ProfileShow
}
}, {
headerMode: 'none'
})
The ForgottenPassword screen is a child Stack Navigator:
import { StackNavigator } from 'react-navigation'
import PasswordResetProcess from './index'
const ForgottenPassword = StackNavigator({
ResetPassword: {
screen: PasswordResetProcess
}
}, {
headerMode: 'none'
})
export default ForgottenPassword
On that index.js Container Component, there is a sub-component that I pass navigation to, like this:
switch (lastCompletedStep) {
case NEW_RESET_REQUEST:
return <InputTel navigation={navigation} />
case INPUT_TEL:
return <ResetPassword navigation={navigation} />
That ResetPassword component is the one in question. It triggers an action creator and passes this.props.navigation into the action creator:
await props.handleResetSubmit(token, props.navigation)
From inside this action creator, props.navigation is available as navigation. I can do this fine:
navigation.navigate('Discover') // see how this is from the root Navigation Stack
I cannot, however, do this:
navigation.dispatch({
type: 'Navigation/RESET',
index: 0,
actions: [{ type: 'Navigate', routeName: 'Discover' }]
})
It throws this error:
[edit] I just tried this and it also generated the same error:
navigation.dispatch(NavigationActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Discover' })]
}))
How do I reset the stack while navigating to Discover from here?
I feel like the answer is to navigate to discover and reset the stack at the same time as some kind of child operation, but I don't know where to begin putting that together. The react-navigation documentation is horrendous for illustrating child to parent operations.
Here is my best guess at what it approximately has to look like:
navigation.dispatch({
type: 'Navigation/NAVIGATE',
routeName: 'Discover',
actions: [{ type: 'Reset', index: 0, key: null }]
})
I just solved it with this code:
navigation.dispatch(NavigationActions.reset({
index: 0,
key: null,
actions: [NavigationActions.navigate({ routeName: 'Discover' })]
}))
The secret was to add key: null, which I have seen people doing before. It is a very important element for times when you are resetting.
Here is the documentation I found that illustrates it:
https://github.com/react-community/react-navigation/issues/1127
I think this works because NavigationActions has knowledge of the root navigation stack, so it works for the same reason navigation.navigate('Discover') worked (in the context of my code in this question).
in version >2 of react navigation, NavigationActions.reset() doesnt work.
You should use StackActions.reset() instead:
import { NavigationActions, StackActions } from 'react-navigation';
const resetStackAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Discover' })],
});
this.props.navigation.dispatch(resetStackAction);
I have few screens which I navigate through one by one. Screen1->screen2-screen3->screen4-Home
What I want is when I go to home then the previous history of navigation should be cleared and back pressing back button should not go to last navigated screen which is screen 4. Currently When I press back button on home screen it takes me back to the last route in the stack which is screen4. I have used below code. It is giving me error no route defined or key Home. Which I have already defined in Screens class. Any help would be appreciated.
const resetAction = NavigationActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Home' })],
});
onPress={() => this.props.navigation.dispatch(resetAction)}
in V5, you can use
this.props.navigation.reset({
index: 0,
routes: [{name: 'Home'}],
});
Using hooks
import {useNavigation} from '#react-navigation/native';
const navigation = useNavigation();
navigation.reset({
index: 0,
routes: [{name: 'Events'}],
});
As it states in the react-navigation docs for reset action, index should be the current active route's index. The error might be related to that.
How to use the index parameter
The index param is used to specify the
current active route. eg: given a basic stack navigation with two
routes Profile and Settings. To reset the state to a point where the
active screen was Settings but have it stacked on top of a Profile
screen, you would do the following:
import { NavigationActions } from 'react-navigation'
const resetAction = NavigationActions.reset({
index: 1,
actions: [
NavigationActions.navigate({ routeName: 'Profile'}),
NavigationActions.navigate({ routeName: 'Settings'})
]
})
this.props.navigation.dispatch(resetAction)
import {NavigationActions} from 'react-navigation';
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'HomeScreen'})
] })
this.props.navigation.dispatch(resetAction);
you can use this, this works for me..
If you use react-navigation#<=4 you can use a Switch Navigator.
You create a Switch Navigator with createSwitchNavigator.
Such navigators do not stack up your navigation.
Add your auth screen/navigator in a Switch Navigator with the home screen/stack.
With that, when you navigate from home to log in, the stacks are not kept.
For more on it:
https://reactnavigation.org/docs/4.x/auth-flow/
With #react-navigation 5.x you can use CommonActions to reset/clear the stack. I'll leave an example here.
import { CommonActions } from '#react-navigation/native';
const handleSigninNavigation = () => {
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: "your-new-route" }]
}));
}
Also you can create your own stack while resetting it. Just pass the names of the routes to routes array and give an index to navigate first.
CommonActions.reset({
index: 1,
routes: [{ name: "home" }, { name: "signin" }]
}));
Above code will reset the current stack with given routes and will navigate to the signin since we set the index to 1.
With typed routes and their parameters
type StateRoute<Route extends keyof MyNavigatorParamList> = {
name: Route;
params: MyNavigatorParamList[Route];
};
const toNavigationStateRoutes = <Route extends keyof MyNavigatorParamList>(
...routes: StateRoute<Route>[]
) => routes;
navigation.dispatch(
CommonActions.reset({
index: 1,
routes: toNavigationStateRoutes(
{
name: 'Home',
params: undefined,
},
{
name: 'Some screen',
params: { id: "..." },
},
),
}),
);
//import
import { NavigationActions, StackActions } from 'react-navigation';
//reset current navigation stack and create new navigation stack
const loginScreenAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'LoginScreen' })],
});
//open new component with new navigation stack
this.props.navigation.dispatch(loginScreenAction)