Reputation: 447
i´m trying to create a custom DrawerNavigator where the items are shown/hidden depending on the redux store state. I´m relative new to react-native :)
All my attempts so far result in an error. My last try, as the 'Providing a custom drawerContent'-docs shows, was to create custom content like this (i changed it to a functional component)
const MainDrawerNavigator = createDrawerNavigator();
export const MainNavigator = state => {
const user = useSelector(state => state.user.user);
//next console lines give different output , i also tried to use useEffect() function but no luck
// console.log("=================state===================");
// console.log(user);
// console.log("===================state=================");
const dispatch = useDispatch();
const isTrainer = useSelector(state => state.user.user.isTrainer) === null ? false : true);
return (
{isTrainer &&
<MainDrawerNavigator.Screen
name="AddUser"
component={AddUserNavigator}
options={{
drawerIcon: props => (
<Ionicons
name={Platform.OS === "android" ? "md-cart" : "ios-cart"}
size={23}
color={props.color}
/>
)
}}
/>
}
<MainDrawerNavigator.Screen
name="Ereignis hinzufügen"
component={MainNavigator}
options={{
drawerIcon: props => (
<Ionicons
name={Platform.OS === "android" ? "md-cart" : "ios-cart"}
size={23}
color={props.color}
/>
)
}}
/>
<MainDrawerNavigator.Screen
title="Deine Daten"
name="UserProfil"
component={UserProfilNavigator}
options={{
drawerIcon: props => (
<Ionicons
name={Platform.OS === "android" ? "md-person" : "md-person"}
size={23}
color={props.color}
/>
)
}}
/>
</MainDrawerNavigator.Navigator>
);
};
So the user logs in the redux store is for user data is set (all ok) and the drawer should consider the roles a user could have and display only the possible routes. Hope i explained it clearly and someone could give the hint in the right direction. Thx Ingo
EDIT: i implement this by using the following code
import React from "react";
import { useSelector } from "react-redux";
import { NavigationContainer } from "@react-navigation/native";
import {
MainNavigator,
AuthNavigator
} from "./MainNavigator";
const AppNavigator = props => {
const isAuth = useSelector(state => !!state.auth.token);
const didTryAutoLogin = useSelector(state => state.auth.didTryAutoLogin);
return (
<NavigationContainer>
{isAuth && <MainNavigator />}
{!isAuth && didTryAutoLogin && <AuthNavigator />}
</NavigationContainer>
);
};
export default AppNavigator;
and in the main App.js
export default function App() {
const [fontLoaded, setFontLoaded] = useState(false);
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={() => {
setFontLoaded(true);
}}
/>
);
}
return (
<Provider store={store}>
<AppNavigator />
</Provider>
);
}
Upvotes: 1
Views: 532
Reputation: 4141
If I'm correct you just want to be able to hide certain items from the drawer? If yes, check out what we use below!
const Item = (props) => {
return (
<View>
<TouchableNativeFeedback onPress={props.onPress}>
<Text>{props.title}</Text>
</TouchableNativeFeedback>
</View>
);
};
const MyDrawer = () => {
const [viewable, setViable] = useState({showScreen1: false, showScreen2: true});
// Do some wizardry which determines what state to show
// Yes yes... wizard... wohoo :D
// Okay done now
return (
<Drawer.Navigator
drawerContent={({navigation}) => (
<SafeAreaView>
<ScrollView>
{
viewable.showScreen1 && (
<Item
title="Some Screen 1"
onPress={() => navigation.navigate('someScreen1')}
/>
)
}
{
viewable.showScreen2 && (
<Item
title="Some Screen 2"
onPress={() => navigation.navigate('someScreen1')}
/>
)
}
</ScrollView>
</SafeAreaView>
)}
>
<Drawer.Screen
component={SomeScreen1}
name="someScreen1"
/>
<Drawer.Screen
component={SomeScreen2}
name="someScreen2"
/>
</Drawer.Navigator>
);
};
Note that I have no idea about redux
but I think you'll manage to create the state and coherent conditions on you own :)
Upvotes: 1
Reputation: 435
I think the original issue was name collision on the "state" variable. You should define your selector function outside of the main function so that it is not recomputed every render. The useSelector hook provides the redux state to the selector function, it is not given to the MainNavigator as a prop. You can also use a single selector to create the "isTrainer" boolean:
// ensuring that user exists in state, and that user.user.isTrainer is true.
const selectUserIsTrainer = state => state.user.user && state.user.user.isTrainer
export const MainNavigator = ({...props}) => {
const userIsTrainer = useSelector(selectUser)
return userIsTrainer ? <TrainerNavigator /> : <NonTrainerNavigator />
}
Upvotes: 0