Inge
Inge

Reputation: 447

Custom DrawerNavigator

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

Answers (2)

Elias
Elias

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

krewllobster
krewllobster

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

Related Questions