Force scrollview to re-render when closing a react-navigation modal? - react-native

I'm opening a modal, nested in a react-navigation TabNavigator.
This modal is used to add, say a teammate, to a Realm database.
When the new teammate is saved, I close the modal and "navigate" back to a ScrollView displaying all the teammates, retrieved from my Realm database.
My problem is that this ScrollView doesn't re-render when closing the modal.
I am not using Redux or any other state manager.
This is the code executed when saving a user:
onButtonPress() {
var teammate = new TeammateModel(this.firstname, this.lastname);
if (this.firstname && this.lastname) {
TeammateService.save(teammate);
this.props.navigation.goBack(null);
}
}
And this is the code of the for the component rendering the ScrollView:
export default class Team extends Component {
componentWillMount() {
teammates = TeammateService.findAll();
}
render() {
return (
<ScrollView>
<List>{teammates.map((teammate) => (
<ListItem
key={teammate.id}
title={`${teammate.firstname} ${teammate.lastname}`}
/>
))}
</List>
</ScrollView>
);
}
}
As requested here's also my routes.js where the navigation happens:
export const TeamStack = StackNavigator({
Team: {
screen: Team,
navigationOptions: ({ navigation }) => ({
headerTitle: 'Team',
headerRight: <Button title="Add" onPress={() => navigation.navigate('EditTeammate')} />
}),
},
})
export const EditTeammateStack = StackNavigator({
EditTeammate: {
screen: EditTeammate,
navigationOptions: ({ navigation }) => ({
headerTitle: 'Teammate',
headerLeft: <Button title="Cancel" onPress={() => navigation.goBack(null)} />
}),
}
})
export const NoteStack = StackNavigator({
EditNote: {
screen: EditNote,
navigationOptions: ({ navigation }) => ({
headerTitle: 'Edit note'
})
}
})
export const Tabs = TabNavigator({
EditNote: {
screen: NoteStack,
navigationOptions: ({ navigation }) => ({
header: { visible: true },
headerTitle: 'Edit note',
tabBarLabel: 'Notes',
tabBarIcon: ({ tintColor }) => <Icon name="list" size={20} color={tintColor} />
}),
},
Team: {
screen: TeamStack,
navigationOptions: ({ navigation }) => ({
header: { visible: true },
headerTitle: 'Team',
tabBarLabel: 'Team',
tabBarIcon: ({ tintColor }) => <Icon name="users" size={20} color={tintColor} />
}),
}
}, {
initialRouteName: 'Team',
});
export const Root = StackNavigator({
Tabs: {
screen: Tabs,
},
EditTeammate: {
screen: EditTeammateStack,
},
}, {
mode: 'modal',
headerMode: 'none'
});
export default Root;
I'm sure I'm doing one (or more) thing(s) wrong. But what? :)

Related

How to add drawerIcon to a drawer navigator that contains a nested stack navigator?

I have a stack navigator which is then nested inside a drawer navigator. I want to have an icon for each of the routes in the stack navigator to then show in the drawer menu.
I have tried to use the navigationOptions to provide each route with a drawer icon in the stack navigator but this did not work.
const StackNavigation = createStackNavigator(
{
Setting: {
screen: SettingScreen,
navigationOptions: {
drawerIcon: ({ tintColor }) => <Feather name="settings" style={{ fontSize: 24, color: tintColor }} />,
},
},
Home: {
screen: HomeScreen,
navigationOptions: {
drawerIcon: ({ tintColor }) => <Feather name="home" style={{ fontSize: 24, color: tintColor }} />,
},
},
},
{
initialRouteName: 'Home',
headerMode: Platform.OS === 'android' ? 'screen' : 'float',
defaultNavigationOptions: ({ navigation }) => ({
headerLeft: <MenuButton navigation={navigation} />,
}),
}
);
const MainNavigation = createDrawerNavigator(
{
Home: {
screen: StackNavigation,
},
},
{
contentComponent: CustomDrawerComponent,
}
);
No icons are applied when attempted this way. Possibly because stack navigator does not have a drawerIcon option? But then I how do I apply them to each route individually...
If you have two paths,
import Icon from 'react-native-vector-icons/FontAwesome';
...
const MainTab = createDrawerNavigator(
{
Home: {
screen: HomeScreen
},
Setting: {
screen: SettingScreen
}
},
{
defaultNavigationOptions: ({ navigation }) => ({
drawerIcon: ({ focused, horizontal, tintColor, image }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === "Home") {
iconName = "home";
} else if (routeName === "Setting") {
iconName = "rocket";
}
return (
<Icon
name={iconName}
size={horizontal ? 20 : 25}
/>
);
}
})
}

Dynamically change bottom navigation icon based on drawer navigation icon

I want to dynamically change the icon of the bottom tab bar icon to the icon of the drawer page i change to. When the drawer open and i select cards page i want the payment icon to change from money to cards icon. Is this possible to achieve ? thanks
bottom tab
const bottomtab = createBottomTabNavigator(
{
home: {
screen: home,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => <Icon name="home" color={tintColor} focused={focused} size={30} />,
},
},
payment: {
screen: paymentdrawerstack,
navigationOptions: ({ navigation }) => {
return{
tabBarIcon: ({ tintColor }) => <Icon name="money" color={tintColor} size={20} />,
}
},
},
},
drawer nav
const paymentdrawerstack = createDrawerNavigator(
{
balance: {
screen: balance,
navigationOptions: ({ navigation }) => {
return{
drawerIcon: ({ tintColor, focused }) => (
<Icon name="money" color={tintColor} focused={focused} size={20} />
),
drawerLabel: 'balance',
}
},
},
cards: {
screen: cards,
navigationOptions: ({ navigation }) => {
return{
drawerIcon: ({ tintColor, focused }) => (
<Icon name="cards" color={tintColor} focused={focused} size={20} />
),
drawerLabel: 'cards',
}
},
},
Try this, use this function to get the active route:
const getActiveRoute = route => {
if (!route.routes || route.routes.length === 0 || route.index >= route.routes.length) {
return route.routeName;
}
const childActiveRoute = route.routes[route.index];
return getActiveRoute(childActiveRoute);
}
And then in navigationOptions of payment, check what the active route is, change the icon accordingly, like so:
payment: {
screen: paymentdrawerstack,
navigationOptions: ({ navigation }) => {
const name = getActiveRoute(navigation.state) === 'cards' ? 'cards' : 'money';
return {
tabBarIcon: ({ tintColor }) => <Icon name={name} color={tintColor} size={20} />,
}
},
},

React Navigation: Is it possible to navigate to the same screen from different stackNavigators?

I'm coding an app that uses react-navigation. My app has a bottom TabNavigator in which each tab consists of a stackNavigator, like so:
Routes.js:
const FirstStack = createStackNavigator({
First: {
screen: FirstScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
const SecondStack = createStackNavigator({
Second: {
screen: SecondScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
const ThirdStack = createStackNavigator({
Third: {
screen: ThirdScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
const FourthStack = createStackNavigator({
Fourth: {
screen: FourthScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
const FifthStack = createStackNavigator({
Fifth: {
screen: FifthScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
export const AppStack = createBottomTabNavigator(
{
First: {
screen: FirstStack,
navigationOptions: {
title: "First",
tabBarLabel: "First",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-home" color={tintColor} size={24} />
)
}
},
Second: {
screen: SecondStack,
navigationOptions: {
title: "Second",
tabBarLabel: "Second",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-clock" color={tintColor} size={24} />
)
}
},
Third: {
screen: ThirdStack,
navigationOptions: {
title: "Third",
tabBarLabel: "Third",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-fitness" color={tintColor} size={24} />
)
}
},
Fourth: {
screen: FourthStack,
navigationOptions: {
title: "Fourth",
tabBarLabel: "Fourth",
tabBarIcon: ({ tintColor }) => (
<Icon
name="ios-cloud-download"
color={tintColor}
size={24}
/>
)
}
},
Fifth: {
screen: FifthStack,
navigationOptions: {
title: "Fifth",
tabBarLabel: "Fifth",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-person" color={tintColor} size={24} />
)
}
}
},
{
initialRouteName: "First",
order: ["First", "Second", "Third", "Fourth", "Fifth"],
tabBarOptions: {
activeTintColor: "white",
inactiveTintColor: "grey",
style: {
backgroundColor: "#121212",
borderTopColor: "#303030"
}
}
}
);
Each stackNavigator inside the tabs in the tabNavigator has its own header so that I can customize the header for each tab, but all headers have a button which should navigate to the profile screen (in this example its the contact icon).
AppToolbar.js:
const appToolbar = props => {
return (
<View style={styles.toolbar}>
<Text style={styles.toolbarTitle}>Title</Text>
<TouchableOpacity onPress={...}>
<Icon
name="ios-contact"
color="grey"
size={30}
style={{ padding: 0, margin: 0, marginRight: 10 }}
/>
</TouchableOpacity>
</View>
);
};
What I want to do is that by pressing the contact icon the app should navigate to the profile screen, what I don't know is if its possible to define like a global route thats accesible from everywhere, Or do I have to add the profile screen to all the stackNavigators so that it is accesible from every screen in every stack?
Thanks in advance!
Found the answer here https://stackoverflow.com/a/50701940/1276438
Use a stackNavigator with the profile stack and the tabNavigator as children, making the tabNavigator the default route.

Functions are not valid as a React child (React-Native)

I can not wrap my head around and understand why am I given this warning, I am using two kinds of navigators ( tab navigator and stack navigator ), in App.js and I cannot seem to get them working correctly
App.js
export const Tabs = TabNavigator({
'FormScreen': {
screen: FormScreen,
navigationOptions: {
tabBarLabel: 'Contact Us',
tabBarIcon: ({ tintColor }) => <Icon name="ios-contact" type="entypo" size={28} color={tintColor} />
}
},
'ListScreen': {
screen: ListScreen,
navigationOptions: {
tabBarLabel: 'Contact List',
tabBarIcon: ({ tintColor }) => <Icon name="list" type="entypo" size={28} color={tintColor} />
}
}
});
export const NavigationScreen = () => {
return StackNavigator(
{
Tabs: {
screen: Tabs,
navigationOptions: {
gesturesEnabled: false
}
}
},
{
headerMode: "none",
mode: "modal"
}
);
};
export default class App extends React.Component {
render() {
return (
<NavigationScreen/>);
}
}

There is no route defined for key

I'm using react native, with redux and react navigation. I have everything setup, however, I'm getting a weird issue/error
In my reducer, I have the following
const initialNavState = {
index: 1,
routes: [
{ key: 'Login', routeName: 'Login' },
{ key: 'ResetPassword', routeName: 'ResetPassword' },
],
};
const initialAuthState = { isLoggedIn: false };
const AppReducer = combineReducers({
nav: (state = initialNavState, action) => {
switch(action.type) {
case 'Login':
return AppNavigator.router.getStateForAction(NavigationActions.back(), state);
case 'Logout':
return AppNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'Login' }), state);
case 'ResetPassword':
return AppNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'ResetPassword' }), state);
case 'Home':
return MainScreenNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'Home' }), state);
default:
return AppNavigator.router.getStateForAction(action, state);
}
}
});
export default AppReducer;
This works fine and I can navigate better my two views but when I add another route
{ key: 'Home', routeName: 'Home' },
I get the following error "There is no route defined for key must by one of login resetpassword.
Not sure what I'm doing wrong?
Updated my router
// Native tab navigation
export const TabsNavigation = TabNavigator({
Home: {
screen: Home,
navigationOptions: ({ navigation }) => ({
tabBarLabel: 'Home',
headerLeft : <DrawerIcon navigation={navigation} />,
tabBarIcon: ({ tintColor }) => <Icon name="home" size={28} color={tintColor} type={"font-awesome"} />
}),
},
Photos: {
screen: Photos,
navigationOptions: {
tabBarLabel: 'Photos',
tabBarIcon: ({ tintColor }) => <Icon name="camera" size={28} color={tintColor} type={"font-awesome"} />
},
},
SiteDiary: {
screen: SiteDiary,
navigationOptions: {
tabBarLabel: 'Site Diary',
tabBarIcon: ({ tintColor }) => <Icon name="cog" size={28} color={tintColor} type={"font-awesome"} />
},
},
});
export const AppNavigator = StackNavigator({
Login: {
screen: Login,
navigationOptions: {
title: "Login",
headerLeft: null
},
initialRouteName : 'Home'
},
ResetPassword: {
screen: ResetPassword,
navigationOptions: {
title: "Reset Password",
headerLeft: null
},
}
});
// Main navigation StackNavigator
export const MainScreenNavigator = StackNavigator({
Home: {
screen: TabsNavigation,
navigationOptions: {
title: "Home",
headerLeft: null,
}
}
});
Index.js (main)
// App state
const AppWithNavigationState = connect( state => ({ nav: state.nav})) (({ dispatch, nav }) => (
<AppNavigator navigation = { addNavigationHelpers ({ dispatch, state: nav })} />
));
class App extends React.Component {
store = createStore(AppReducer, undefined, autoRehydrate());
componentDidMount() {
persistStore(this.store, { storage: AsyncStorage });
}
render() {
return (
<Provider store={this.store}>
<AppWithNavigationState />
</Provider>
);
}
}
AppRegistry.registerComponent('App', () => App);
export default App;
I the core issue is with AppNavigator on my main file, I'm trying to have
AppNavigator -- this holds all the public login views
MainScreenNavigator -- This is the main app
and later add a darwer but right now would be nice to get just this working.
The issue is I'm not sure how you can jump between StackNavigator