反应本机登录和登录导航 - 正确的方式建议
React native login and loggedin navigation - correct way advise
请有人建议正确的方法来建立登录和登录导航系统。我现在正在做的方式是使用 use-between 包共享状态并显示正确的导航。但我不确定这是正确的做法。请有人指出正确的方向和正确的方法来实现同样的目标。下面是我的代码。
import React, { useEffect } from "react";
import { useLoggedInUserState } from "./core/state";
import { useBetween } from "use-between";
import { getLoggedInUser } from "./core/utils";
//navigation
import LoginNav from "./nav/LoginNav";
import LoggedInNav from "./nav/LoggedInNav";
export default function App() {
//shared states
const { loggedInUser, setLoggedInUser } = useBetween(useLoggedInUserState);
//check storage and store user in state
useEffect(async () => {
const objUser = await getLoggedInUser();
setLoggedInUser(objUser);
}, []);
//render
return loggedInUser ? <LoggedInNav loggedInUser={loggedInUser} /> : <LoginNav />;
}
//login nav
登录导航
import React, { memo } from "react";
import { createDrawerNavigator } from "@react-navigation/drawer";
import { NavigationContainer, CommonActions, useNavigation } from "@react-navigation/native";
import { Appbar, BottomNavigation, Menu, useTheme, Button } from "react-native-paper";
import { Text, Image, View, TouchableOpacity } from "react-native";
import { AboutScreen, TermsScreen, CartScreen, PaymentScreen, NotificationTestScreen, VehicleEditScreen } from "../screens";
import Sidebar from "../components/Sidebar";
import BottomNav from "./BottomNav";
const Drawer = createDrawerNavigator();
//LoggedIn Navigation
const LoggedInNav = (propsLoggedIn) => {
const { colors, background } = useTheme();
//const [visible, setVisible] = React.useState(false); //used by appbar
//const openMenu = () => setVisible(true); //used by appbar
//const closeMenu = () => setVisible(false); //used by appbar
const cartCount = 40; //will be from state
return (
<NavigationContainer>
<Drawer.Navigator
screenOptions={(propsNavigator) => ({
headerShown: true,
headerLeft: () => (
<View
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
flexDirection: "row",
}}
>
<TouchableOpacity onPress={() => propsNavigator.navigation.openDrawer()}>
<Image
source={require("../assets/images/menu.png")}
style={{
tintColor: "#fff",
width: 28,
height: 28,
position: "relative",
marginLeft: 8,
}}
/>
</TouchableOpacity>
<TouchableOpacity onPress={() => propsNavigator.navigation.navigate("Dashboard")}>
<Image
source={require("../assets/images/home.png")}
style={{
tintColor: "#fff",
width: 28,
height: 28,
position: "relative",
marginLeft: 8,
}}
/>
</TouchableOpacity>
</View>
),
headerRight: () => (
<View
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
flexDirection: "row",
}}
>
<TouchableOpacity
onPress={() => {
propsNavigator.navigation.navigate("NotificationTest");
}}
>
<Image
source={require("../assets/images/bell.png")}
style={{
tintColor: "#fff",
width: 32,
height: 32,
position: "relative",
marginRight: 4,
}}
/>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
propsNavigator.navigation.navigate("Cart");
}}
>
<Image
source={require("../assets/images/cart.png")}
style={{
tintColor: "#fff",
width: 32,
height: 32,
position: "relative",
marginRight: 16,
}}
/>
</TouchableOpacity>
{cartCount > 0 ? (
<View
style={{
position: "absolute",
backgroundColor: "red",
width: 16,
height: 16,
borderRadius: 15 / 2,
right: 10,
top: +8,
alignItems: "center",
justifyContent: "center",
}}
>
<Text
style={{
alignItems: "center",
justifyContent: "center",
color: "#FFFFFF",
fontSize: 8,
}}
>
{cartCount}
</Text>
</View>
) : null}
</View>
),
headerStyle: {
backgroundColor: colors.primary,
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "bold",
},
/* header using react native paper
header: ({ navigation, back, route }) => (
<Appbar.Header>
{back ? <Appbar.BackAction onPress={navigation.goBack} /> : null}
<Appbar.Content title={route.params.title ? route.params.title : "Between Detailing"} />
{!back ? (
<Menu visible={visible} onDismiss={closeMenu} anchor={<Appbar.Action icon="menu" color="white" onPress={openMenu} />}>
<Menu.Item
onPress={() => {
navigation.navigate("Dashboard");
}}
title="Dashboard"
/>
<Menu.Item
onPress={() => {
navigation.navigate("About");
}}
title="About"
/>
<Menu.Item
onPress={() => {
navigation.navigate("Terms");
}}
title="Terms"
//disabled
/>
</Menu>
) : null}
</Appbar.Header>
),header using react native paper */
})}
drawerContent={(drawerContentProps) => <Sidebar loggedInUser={propsLoggedIn.loggedInUser} {...drawerContentProps} />}
>
<Drawer.Screen name="Dashboard" component={BottomNav} initialParams={{ title: "Dashboard" }} />
<Drawer.Screen name="About" component={AboutScreen} initialParams={{ title: "About" }} />
<Drawer.Screen name="Terms" component={TermsScreen} initialParams={{ title: "Terms" }} />
<Drawer.Screen name="VehicleEdit" component={VehicleEditScreen} initialParams={{ title: "Edit Vehicle" }} />
<Drawer.Screen name="Cart" component={CartScreen} initialParams={{ title: "Cart" }} options={{ drawerItemStyle: { display: "none" } }} />
<Drawer.Screen name="Payment" component={PaymentScreen} initialParams={{ title: "Payment" }} options={{ drawerItemStyle: { display: "none" } }} />
<Drawer.Screen name="NotificationTest" component={NotificationTestScreen} initialParams={{ title: "NotificationTest" }} options={{ drawerItemStyle: { display: "none" } }} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default memo(LoggedInNav);
感谢您指出 link,我认为我的方向几乎是正确的。我已根据文章对我的代码进行了一些修改,并且运行良好。
我唯一担心的是我在 LoginNav 和 LoggedInNav 中都有 2 个导航容器 1,如下所示。在这种情况下有什么意见,这样做是否正确?
//登录导航
const LoginNav = () => {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="Home"
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen name="ForgotPassword" component={ForgotPasswordScreen} />
<Stack.Screen name="Dashboard" component={DashboardScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
//登录导航
//LoggedIn Navigation
const LoggedInNav = (propsLoggedIn) => {
const { colors, background } = useTheme();
//const [visible, setVisible] = React.useState(false); //used by appbar
//const openMenu = () => setVisible(true); //used by appbar
//const closeMenu = () => setVisible(false); //used by appbar
const cartCount = 40; //will be from state
return (
<NavigationContainer>
<Drawer.Navigator
drawerContent={(drawerContentProps) => <Sidebar loggedInUser={propsLoggedIn.loggedInUser} {...drawerContentProps} />}
>
<Drawer.Screen name="Dashboard" component={BottomNav} initialParams={{ title: "Dashboard" }} />
<Drawer.Screen name="About" component={AboutScreen} initialParams={{ title: "About" }} />
<Drawer.Screen name="Terms" component={TermsScreen} initialParams={{ title: "Terms" }} />
<Drawer.Screen name="VehicleEdit" component={VehicleEditScreen} initialParams={{ title: "Edit Vehicle" }} />
<Drawer.Screen name="Cart" component={CartScreen} initialParams={{ title: "Cart" }} options={{ drawerItemStyle: { display: "none" } }} />
<Drawer.Screen name="Payment" component={PaymentScreen} initialParams={{ title: "Payment" }} options={{ drawerItemStyle: { display: "none" } }} />
<Drawer.Screen name="NotificationTest" component={NotificationTestScreen} initialParams={{ title: "NotificationTest" }} options={{ drawerItemStyle: { display: "none" } }} />
</Drawer.Navigator>
</NavigationContainer>
);
};
//导航
import LoginNav from "./nav/LoginNav";
import LoggedInNav from "./nav/LoggedInNav";
export default function App() {
//shared states
const { loggedInUser, setLoggedInUser } = useBetween(useLoggedInUserState);
//common states
const [loading, setLoading] = useState(false);
//check storage and store user in state
useEffect(async () => {
setLoading(true);
const objUser = await getLoggedInUser();
setLoggedInUser(objUser);
setLoading(false);
}, []);
//render
if (!loading) {
return loggedInUser ? <LoggedInNav loggedInUser={loggedInUser} /> : <LoginNav />;
} else {
return (
<View>
<Text>Loading...</Text>
</View>
);
}
}
推荐的最佳做法是使用单一 NavigationContainer
。我认为为所有导航状态提供单一真实来源很重要。
尝试重构代码如下:
export default function App() {
//shared states
const { loggedInUser, setLoggedInUser } = useBetween(useLoggedInUserState);
//common states
const [loading, setLoading] = useState(false);
//check storage and store user in state
useEffect(async () => {
setLoading(true);
const objUser = await getLoggedInUser();
setLoggedInUser(objUser);
setLoading(false);
}, []);
//render
return !loading ? (
<NavigationContainer>
{loggedInUser ? (
<Drawer.Navigator
drawerContent={(drawerContentProps) => (
<Sidebar
loggedInUser={propsLoggedIn.loggedInUser}
{...drawerContentProps}
/>
)}
>
<Drawer.Screen
name="Dashboard"
component={BottomNav}
initialParams={{ title: "Dashboard" }}
/>
<Drawer.Screen
name="About"
component={AboutScreen}
initialParams={{ title: "About" }}
/>
<Drawer.Screen
name="Terms"
component={TermsScreen}
initialParams={{ title: "Terms" }}
/>
<Drawer.Screen
name="VehicleEdit"
component={VehicleEditScreen}
initialParams={{ title: "Edit Vehicle" }}
/>
<Drawer.Screen
name="Cart"
component={CartScreen}
initialParams={{ title: "Cart" }}
options={{ drawerItemStyle: { display: "none" } }}
/>
<Drawer.Screen
name="Payment"
component={PaymentScreen}
initialParams={{ title: "Payment" }}
options={{ drawerItemStyle: { display: "none" } }}
/>
<Drawer.Screen
name="NotificationTest"
component={NotificationTestScreen}
initialParams={{ title: "NotificationTest" }}
options={{ drawerItemStyle: { display: "none" } }}
/>
</Drawer.Navigator>
) : (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="Home"
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen
name="ForgotPassword"
component={ForgotPasswordScreen}
/>
<Stack.Screen name="Dashboard" component={DashboardScreen} />
</Stack.Navigator>
)}
</NavigationContainer>
) : (
<View>
<Text>Loading...</Text>
</View>
);
}
请有人建议正确的方法来建立登录和登录导航系统。我现在正在做的方式是使用 use-between 包共享状态并显示正确的导航。但我不确定这是正确的做法。请有人指出正确的方向和正确的方法来实现同样的目标。下面是我的代码。
import React, { useEffect } from "react";
import { useLoggedInUserState } from "./core/state";
import { useBetween } from "use-between";
import { getLoggedInUser } from "./core/utils";
//navigation
import LoginNav from "./nav/LoginNav";
import LoggedInNav from "./nav/LoggedInNav";
export default function App() {
//shared states
const { loggedInUser, setLoggedInUser } = useBetween(useLoggedInUserState);
//check storage and store user in state
useEffect(async () => {
const objUser = await getLoggedInUser();
setLoggedInUser(objUser);
}, []);
//render
return loggedInUser ? <LoggedInNav loggedInUser={loggedInUser} /> : <LoginNav />;
}
//login nav
登录导航
import React, { memo } from "react";
import { createDrawerNavigator } from "@react-navigation/drawer";
import { NavigationContainer, CommonActions, useNavigation } from "@react-navigation/native";
import { Appbar, BottomNavigation, Menu, useTheme, Button } from "react-native-paper";
import { Text, Image, View, TouchableOpacity } from "react-native";
import { AboutScreen, TermsScreen, CartScreen, PaymentScreen, NotificationTestScreen, VehicleEditScreen } from "../screens";
import Sidebar from "../components/Sidebar";
import BottomNav from "./BottomNav";
const Drawer = createDrawerNavigator();
//LoggedIn Navigation
const LoggedInNav = (propsLoggedIn) => {
const { colors, background } = useTheme();
//const [visible, setVisible] = React.useState(false); //used by appbar
//const openMenu = () => setVisible(true); //used by appbar
//const closeMenu = () => setVisible(false); //used by appbar
const cartCount = 40; //will be from state
return (
<NavigationContainer>
<Drawer.Navigator
screenOptions={(propsNavigator) => ({
headerShown: true,
headerLeft: () => (
<View
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
flexDirection: "row",
}}
>
<TouchableOpacity onPress={() => propsNavigator.navigation.openDrawer()}>
<Image
source={require("../assets/images/menu.png")}
style={{
tintColor: "#fff",
width: 28,
height: 28,
position: "relative",
marginLeft: 8,
}}
/>
</TouchableOpacity>
<TouchableOpacity onPress={() => propsNavigator.navigation.navigate("Dashboard")}>
<Image
source={require("../assets/images/home.png")}
style={{
tintColor: "#fff",
width: 28,
height: 28,
position: "relative",
marginLeft: 8,
}}
/>
</TouchableOpacity>
</View>
),
headerRight: () => (
<View
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
flexDirection: "row",
}}
>
<TouchableOpacity
onPress={() => {
propsNavigator.navigation.navigate("NotificationTest");
}}
>
<Image
source={require("../assets/images/bell.png")}
style={{
tintColor: "#fff",
width: 32,
height: 32,
position: "relative",
marginRight: 4,
}}
/>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
propsNavigator.navigation.navigate("Cart");
}}
>
<Image
source={require("../assets/images/cart.png")}
style={{
tintColor: "#fff",
width: 32,
height: 32,
position: "relative",
marginRight: 16,
}}
/>
</TouchableOpacity>
{cartCount > 0 ? (
<View
style={{
position: "absolute",
backgroundColor: "red",
width: 16,
height: 16,
borderRadius: 15 / 2,
right: 10,
top: +8,
alignItems: "center",
justifyContent: "center",
}}
>
<Text
style={{
alignItems: "center",
justifyContent: "center",
color: "#FFFFFF",
fontSize: 8,
}}
>
{cartCount}
</Text>
</View>
) : null}
</View>
),
headerStyle: {
backgroundColor: colors.primary,
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "bold",
},
/* header using react native paper
header: ({ navigation, back, route }) => (
<Appbar.Header>
{back ? <Appbar.BackAction onPress={navigation.goBack} /> : null}
<Appbar.Content title={route.params.title ? route.params.title : "Between Detailing"} />
{!back ? (
<Menu visible={visible} onDismiss={closeMenu} anchor={<Appbar.Action icon="menu" color="white" onPress={openMenu} />}>
<Menu.Item
onPress={() => {
navigation.navigate("Dashboard");
}}
title="Dashboard"
/>
<Menu.Item
onPress={() => {
navigation.navigate("About");
}}
title="About"
/>
<Menu.Item
onPress={() => {
navigation.navigate("Terms");
}}
title="Terms"
//disabled
/>
</Menu>
) : null}
</Appbar.Header>
),header using react native paper */
})}
drawerContent={(drawerContentProps) => <Sidebar loggedInUser={propsLoggedIn.loggedInUser} {...drawerContentProps} />}
>
<Drawer.Screen name="Dashboard" component={BottomNav} initialParams={{ title: "Dashboard" }} />
<Drawer.Screen name="About" component={AboutScreen} initialParams={{ title: "About" }} />
<Drawer.Screen name="Terms" component={TermsScreen} initialParams={{ title: "Terms" }} />
<Drawer.Screen name="VehicleEdit" component={VehicleEditScreen} initialParams={{ title: "Edit Vehicle" }} />
<Drawer.Screen name="Cart" component={CartScreen} initialParams={{ title: "Cart" }} options={{ drawerItemStyle: { display: "none" } }} />
<Drawer.Screen name="Payment" component={PaymentScreen} initialParams={{ title: "Payment" }} options={{ drawerItemStyle: { display: "none" } }} />
<Drawer.Screen name="NotificationTest" component={NotificationTestScreen} initialParams={{ title: "NotificationTest" }} options={{ drawerItemStyle: { display: "none" } }} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default memo(LoggedInNav);
感谢您指出 link,我认为我的方向几乎是正确的。我已根据文章对我的代码进行了一些修改,并且运行良好。
我唯一担心的是我在 LoginNav 和 LoggedInNav 中都有 2 个导航容器 1,如下所示。在这种情况下有什么意见,这样做是否正确?
//登录导航
const LoginNav = () => {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="Home"
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen name="ForgotPassword" component={ForgotPasswordScreen} />
<Stack.Screen name="Dashboard" component={DashboardScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
//登录导航
//LoggedIn Navigation
const LoggedInNav = (propsLoggedIn) => {
const { colors, background } = useTheme();
//const [visible, setVisible] = React.useState(false); //used by appbar
//const openMenu = () => setVisible(true); //used by appbar
//const closeMenu = () => setVisible(false); //used by appbar
const cartCount = 40; //will be from state
return (
<NavigationContainer>
<Drawer.Navigator
drawerContent={(drawerContentProps) => <Sidebar loggedInUser={propsLoggedIn.loggedInUser} {...drawerContentProps} />}
>
<Drawer.Screen name="Dashboard" component={BottomNav} initialParams={{ title: "Dashboard" }} />
<Drawer.Screen name="About" component={AboutScreen} initialParams={{ title: "About" }} />
<Drawer.Screen name="Terms" component={TermsScreen} initialParams={{ title: "Terms" }} />
<Drawer.Screen name="VehicleEdit" component={VehicleEditScreen} initialParams={{ title: "Edit Vehicle" }} />
<Drawer.Screen name="Cart" component={CartScreen} initialParams={{ title: "Cart" }} options={{ drawerItemStyle: { display: "none" } }} />
<Drawer.Screen name="Payment" component={PaymentScreen} initialParams={{ title: "Payment" }} options={{ drawerItemStyle: { display: "none" } }} />
<Drawer.Screen name="NotificationTest" component={NotificationTestScreen} initialParams={{ title: "NotificationTest" }} options={{ drawerItemStyle: { display: "none" } }} />
</Drawer.Navigator>
</NavigationContainer>
);
};
//导航
import LoginNav from "./nav/LoginNav";
import LoggedInNav from "./nav/LoggedInNav";
export default function App() {
//shared states
const { loggedInUser, setLoggedInUser } = useBetween(useLoggedInUserState);
//common states
const [loading, setLoading] = useState(false);
//check storage and store user in state
useEffect(async () => {
setLoading(true);
const objUser = await getLoggedInUser();
setLoggedInUser(objUser);
setLoading(false);
}, []);
//render
if (!loading) {
return loggedInUser ? <LoggedInNav loggedInUser={loggedInUser} /> : <LoginNav />;
} else {
return (
<View>
<Text>Loading...</Text>
</View>
);
}
}
推荐的最佳做法是使用单一 NavigationContainer
。我认为为所有导航状态提供单一真实来源很重要。
尝试重构代码如下:
export default function App() {
//shared states
const { loggedInUser, setLoggedInUser } = useBetween(useLoggedInUserState);
//common states
const [loading, setLoading] = useState(false);
//check storage and store user in state
useEffect(async () => {
setLoading(true);
const objUser = await getLoggedInUser();
setLoggedInUser(objUser);
setLoading(false);
}, []);
//render
return !loading ? (
<NavigationContainer>
{loggedInUser ? (
<Drawer.Navigator
drawerContent={(drawerContentProps) => (
<Sidebar
loggedInUser={propsLoggedIn.loggedInUser}
{...drawerContentProps}
/>
)}
>
<Drawer.Screen
name="Dashboard"
component={BottomNav}
initialParams={{ title: "Dashboard" }}
/>
<Drawer.Screen
name="About"
component={AboutScreen}
initialParams={{ title: "About" }}
/>
<Drawer.Screen
name="Terms"
component={TermsScreen}
initialParams={{ title: "Terms" }}
/>
<Drawer.Screen
name="VehicleEdit"
component={VehicleEditScreen}
initialParams={{ title: "Edit Vehicle" }}
/>
<Drawer.Screen
name="Cart"
component={CartScreen}
initialParams={{ title: "Cart" }}
options={{ drawerItemStyle: { display: "none" } }}
/>
<Drawer.Screen
name="Payment"
component={PaymentScreen}
initialParams={{ title: "Payment" }}
options={{ drawerItemStyle: { display: "none" } }}
/>
<Drawer.Screen
name="NotificationTest"
component={NotificationTestScreen}
initialParams={{ title: "NotificationTest" }}
options={{ drawerItemStyle: { display: "none" } }}
/>
</Drawer.Navigator>
) : (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="Home"
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen
name="ForgotPassword"
component={ForgotPasswordScreen}
/>
<Stack.Screen name="Dashboard" component={DashboardScreen} />
</Stack.Navigator>
)}
</NavigationContainer>
) : (
<View>
<Text>Loading...</Text>
</View>
);
}