我在“ LoginComponent”中的“ onLogin”功能有问题。按下处理该功能的TouchableOpacity之后,我希望将用户定向到“ HomeComponent”,但我却得到了这个console.error:“使用有效内容导航的操作...未处理...”任何人都知道为什么会这样呢?任何帮助将不胜感激。谢谢!
import React, { Component } from 'react';
import 'react-native-gesture-handler';
import { createStackNavigator } from '@react-navigation/stack';
import WelcomeScreen from './WelcomeComponent';
import LoginScreen from './LoginComponent';
import RegisterScreen from './RegisterComponent';
import HomeScreen from './HomeComponent';
import { NavigationContainer } from '@react-navigation/native';
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
import { AsyncStorage } from 'react-native';
const AuthStack = createStackNavigator();
const AuthStackScreen = () => {
return <AuthStack.Navigator initialRouteName="Welcome">
<AuthStack.Screen name="Welcome" component={WelcomeScreen} />
<AuthStack.Screen name="Login" component={LoginScreen} />
<AuthStack.Screen name="Register" component={RegisterScreen} />
</AuthStack.Navigator>
};
const HomeTab = createMaterialBottomTabNavigator();
const HomeTabScreen = () => {
return <HomeTab.Navigator initialRouteName="Home">
<HomeTab.Screen name="Home" component={HomeScreen} />
</HomeTab.Navigator>
}
class Navigation extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false,
};
this.loginStatusCheck();
}
loginStatusCheck = async () => {
const userToken = await AsyncStorage.getItem("userprofile");
if(userToken) {
this.setState({ isLoggedIn: true })
} else {
this.setState({ isLoggedIn: false })
}
}
render() {
return(
<NavigationContainer>
{this.state.isLoggedIn ? <AuthStackScreen /> : <HomeTabScreen />}
</NavigationContainer>
);
};
};
export default Navigation;
import React, { Component } from 'react';
import { StyleSheet, SafeAreaView, ScrollView, View, TouchableOpacity, Text, Linking, AsyncStorage } from 'react-native';
import { Input, CheckBox } from 'react-native-elements';
import { FontAwesome } from '@expo/vector-icons';
class LoginScreen extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password:"",
token: "",
remember: false
};
this.getData();
};
handleUsernameChange = username => {
this.setState({ username })
};
handlePasswordChange = password => {
this.setState({ password })
};
onLogin = async () => {
try {
await AsyncStorage.setItem("userprofile", JSON.stringify({ username: this.state.username, password: this.state.password }));
this.props.navigation.navigate("Home", {
screen: "HomeScreen",
});
} catch (err) {
console.log(err);
}
};
getData = async () => {
try {
const userprofile = await AsyncStorage.getItem("userprofile");
const userProfile = JSON.parse(userprofile);
if (userProfile !== null) {
this.setState({ ...userProfile })
}
if (username !== null) {
this.setState({ username })
}
if (password !== null) {
this.setState({ password })
}
} catch (err) {
console.log(err);
}
}
render() {
const { username, password } = this.state;
return (
<SafeAreaView style={styles.container}>
<ScrollView>
<Text style={styles.titleText}>Login</Text>
<Text style={styles.fillerText}>Hi there! Nice to see you again.</Text>
<Input
inputStyle={{color: 'white'}}
placeholder="Enter username"
onChangeText={this.handleUsernameChange}
value={username}
keyboardType="email-address"
autoCapitalize="none"
leftIcon={{ type: 'font-awesome', name: 'user-circle-o', color: 'white', marginRight: 10 }}
/>
<Input
inputStyle={{color: 'white'}}
placeholder="Password"
secureTextEntry
onChangeText={this.handlePasswordChange}
value={password}
leftIcon={{ type: 'font-awesome', name: 'lock', color: 'white', marginRight: 10 }}
/>
<CheckBox
title="Remember Me"
checked={this.state.remember}
onPress={() => this.setState({remember: !this.state.remember})}
containerStyle={styles.rememberCheckbox}
textStyle={{color: 'white'}}
checkedColor="crimson"
/>
<TouchableOpacity
style={styles.loginButton}
title="Login" type="submit"
onPress={this.onLogin}
>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<Text style={{textAlign: 'center', color: 'grey', marginTop: 20}}>
OR use an account from one of the following:
</Text>
<View style={styles.buttonsContainer}>
<TouchableOpacity style={styles.twitterButton}>
<FontAwesome name="twitter" color="white" style={{marginRight: 5}}/>
<Text style={{color: 'white'}}>Twitter</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.facebookButton}>
<FontAwesome name="facebook-square" color="white" style={{marginRight: 5}}/>
<Text style={{color: 'white'}}>Facebook</Text>
</TouchableOpacity>
</View>
<View style={{alignItems: 'center'}}>
<TouchableOpacity style={styles.googleButton}>
<FontAwesome name="google" color="black" style={{marginRight: 5}}/>
<Text style={{color: 'grey'}}>Google</Text>
</TouchableOpacity>
</View>
<View style={styles.linkContainer}>
<TouchableOpacity style={{marginTop: 75}} onPress={() => Linking.openURL('#')}>
<Text style={{color: 'white'}}>
Forgot Your Password?
</Text>
</TouchableOpacity>
<TouchableOpacity style={{marginTop: 75, marginLeft: 210}} onPress={() => Linking.openURL('#')}>
<Text style={{color: 'white'}}>
Register
</Text>
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
);
};
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'black'
},
buttonsContainer: {
flex: 2,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row'
},
linkContainer: {
flex: 3,
justifyContent: 'center',
flexDirection: 'row'
},
titleText: {
fontSize: 26,
color: 'white',
marginBottom: 30,
marginTop: 20
},
fillerText: {
color: 'grey',
marginBottom: 20
},
loginButton: {
backgroundColor: 'crimson',
paddingVertical: 17,
paddingHorizontal: 25,
borderRadius: 20,
textAlign: 'center'
},
buttonText: {
color: 'white',
fontSize: 18,
textAlign: 'center'
},
twitterButton: {
backgroundColor: '#00acee',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
facebookButton: {
backgroundColor: '#4267B2',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
googleButton: {
backgroundColor: '#FFFFFF',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
rememberCheckbox: {
margin: 10,
marginBottom: 20,
backgroundColor: null
}
});
export default LoginScreen;
答案 0 :(得分:0)
我认为在navigate
组件中不必使用LoginScreen
,因为您已经编写了代码,可以根据isLoggedIn
的值有条件地呈现两个导航器。 / p>
当前实现中缺少的是一种从isLoggedIn
组件内部更新LoginScreen
的方法。然后,如果isLoggedIn
被更新并设置为true
,则Navigation
组件将被重新渲染,并且显示HomeScreen
组件而无需导航。
我选择在这里使用react context,但是如果您愿意的话,也可以将这种方法与redux之类的方法一起使用。使用类似react context之类的原因是为了能够在组件之间轻松传递isLoggedIn
及其设置器。
我将给出一个更通用的示例,因为这样更容易说明这种方法:
// Imports and other stuff...
const LoginContext = React.createContext([null, () => {}]);
const LoginContextProvider = props => {
const [isLoggedIn, setIsLoggedIn] = React.useState(false);
return (
<LoginContext.Provider value={[isLoggedIn, setIsLoggedIn]}>
{props.children}
</LoginContext.Provider>
);
};
const HomeScreen = () => {
return (
<View>
<Text>HomeScreen</Text>
</View>
);
};
const LoginScreen = () => {
const [isLoggedIn, setIsLoggedIn] = React.useContext(LoginContext);
return (
<View>
<Text>LoginScreen</Text>
<Button
title="login"
onPress={() => {
setIsLoggedIn(true);
}}
/>
</View>
);
};
const HomeTabScreen = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
</Tab.Navigator>
);
};
const AuthStackScreen = ({ navigation }) => {
return (
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
</Stack.Navigator>
);
};
const Navigation = () => {
const [isLoggedIn, setIsLoggedIn] = React.useContext(LoginContext);
return (
<NavigationContainer>
{isLoggedIn ? <HomeTabScreen /> : <AuthStackScreen />}
</NavigationContainer>
);
};
export default function App() {
return (
<LoginContextProvider>
<Navigation />
</LoginContextProvider>
);
}
因此,上面显示的方法是创建一个保存您的isLoggedIn
状态和设置器(setIsLoggedIn
)的提供程序。然后,当我们使用此提供程序包装Navigation
时,便可以从提供程序内部的任何组件访问isLogged
和setIsLoggedIn
,从而允许我们更新{{1 }} 零件。此状态更新后,提供者及其内部的所有内容(即isLogged
)将重新呈现并显示LoginScreen
组件。
通常,惯例是将大多数与React上下文相关的内容放入其自己的文件中,并将部件导入所需的组件中,但是出于演示目的,我没有这样做。