反应本机导航 - componentDidMount() 触发了两次
react native navigation - componentDidMount() fired twice
我是 React Native 的新手。我正在尝试构建一个具有 Splash
屏幕的应用程序,如果用户尚未通过身份验证,该屏幕稍后会导航到 Login
屏幕,如果用户已通过身份验证,则导航到 Main
屏幕。这是使用 this.props.navigation.navigate()
完成的
问题是 Splash
组件会被挂载两次。我通过在 Splash
的 componentDidMount()
内打印来检查这一点。正因为如此,Login/Main画面进入了两次,看起来很不爽。有没有什么办法解决这一问题?
另外,我想在屏幕从 Splash
变为 Login
或 Main
时使用 setTimeout()
添加一些延迟。无论如何去做这个?
这是我的代码:
index.js
import React from 'react';
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
import reduxThunk from 'redux-thunk';
import reducers from './src/reducers';
import { StyleSheet } from 'react-native';
import LoginScreen from './src/components/Login/LoginScreen';
import Splash from './src/components/Login/Splash';
import Navigation from './src/components/Navigation/Navigation';
import { Font } from 'expo';
import {
createStackNavigator
} from 'react-navigation';
const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
const store = createStoreWithMiddleware(reducers);
const persistor = persistStore(store);
export default class App extends React.Component {
constructor(props){
super(props);
this.state = {
fontLoaded: false,
currentScreen: 'Splash',
};
setTimeout(() => this.setState({currentScreen: 'Login'}), 2000);
}
async componentDidMount() {
await Font.loadAsync({
'Quicksand': require('./assets/fonts/Quicksand-Regular.ttf'),
'Quicksand-Medium': require('./assets/fonts/Quicksand-Medium.ttf'),
'Quicksand-Bold': require('./assets/fonts/Quicksand-Bold.ttf'),
});
this.setState({ fontLoaded: true });
}
render() {
const MainNavigator = createStackNavigator({
Splash: { screen: Splash },
Main: { screen: Navigation },
Login: { screen: LoginScreen },
})
if (this.state.fontLoaded)
return (
<Provider store={store}>
<MainNavigator></MainNavigator>
</Provider>
)
else return null;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Splash.js
import React from 'react';
import { StyleSheet, Text, View, ImageBackground, Image, Button } from 'react-native';
import bgImage from '../../../assets/images/login-background2.png';
import logo from '../../../assets/images/app-logo.png';
import { connect } from 'react-redux';
import { checkAuth } from '../../actions/auth.actions';
class Splash extends React.Component {
static navigationOptions ={
header: null
}
constructor(props){
super(props);
this.state = {
stillLoading: true,
}
}
componentDidMount() {
this.props.checkAuth();
}
render() {
if (this.props.authState.isLoginPending)
return (
<ImageBackground source={bgImage} style={styles.backgroundContainer}>
<View style={styles.logoContainer}>
<Image source={logo} style={styles.logo}></Image>
<Text style={styles.logoText}> Welcome to HealthScout</Text>
</View>
</ImageBackground>
);
else if (this.props.authState.isLoginSuccess){
setTimeout(() => this.props.navigation.navigate('Main'));
return null;
}
else{
setTimeout(() => this.props.navigation.navigate('Login'));
return null;
}
}
}
const mapStateToProps = state => {
return {
authState: state.authState
}
}
const mapDispatchToProps = dispatch => {
return {
checkAuth: () => dispatch(checkAuth()),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Splash);
const styles = StyleSheet.create({
backgroundContainer: {
flex: 1,
alignItems: 'center',
width: null,
height: null,
justifyContent: 'center',
},
logoContainer: {
alignItems: 'center',
},
logo: {
width: 110,
height: 149,
},
logoText: {
color: '#fff',
fontSize: 40,
fontFamily: 'Quicksand',
opacity: 0.7,
marginTop: 20,
marginBottom: 10,
textAlign: 'center',
},
});
解决方案
从render
中取出createStackNavigator
。
更好的方法是在 App
class.
上方环绕屏幕
const MainNavigator = createStackNavigator({
Splash: { screen: Splash },
Main: { screen: Navigation },
Login: { screen: LoginScreen },
})
export default class App extends React.Component {
...
为什么?
render
是 运行 重复取决于各种条件,如改变状态、道具等。
而且您的代码看起来在 render
中使用 createStackNavigation
创建了多个组件。拿出来:)
p.s 如果您想在显示主屏幕之前等待加载字体,只需在加载字体后从初始屏幕切换到主屏幕即可。因此,更好的方法是在 SplashScreen
中加载字体并执行您想要的操作。
我是 React Native 的新手。我正在尝试构建一个具有 Splash
屏幕的应用程序,如果用户尚未通过身份验证,该屏幕稍后会导航到 Login
屏幕,如果用户已通过身份验证,则导航到 Main
屏幕。这是使用 this.props.navigation.navigate()
完成的
问题是 Splash
组件会被挂载两次。我通过在 Splash
的 componentDidMount()
内打印来检查这一点。正因为如此,Login/Main画面进入了两次,看起来很不爽。有没有什么办法解决这一问题?
另外,我想在屏幕从 Splash
变为 Login
或 Main
时使用 setTimeout()
添加一些延迟。无论如何去做这个?
这是我的代码:
index.js
import React from 'react';
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
import reduxThunk from 'redux-thunk';
import reducers from './src/reducers';
import { StyleSheet } from 'react-native';
import LoginScreen from './src/components/Login/LoginScreen';
import Splash from './src/components/Login/Splash';
import Navigation from './src/components/Navigation/Navigation';
import { Font } from 'expo';
import {
createStackNavigator
} from 'react-navigation';
const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
const store = createStoreWithMiddleware(reducers);
const persistor = persistStore(store);
export default class App extends React.Component {
constructor(props){
super(props);
this.state = {
fontLoaded: false,
currentScreen: 'Splash',
};
setTimeout(() => this.setState({currentScreen: 'Login'}), 2000);
}
async componentDidMount() {
await Font.loadAsync({
'Quicksand': require('./assets/fonts/Quicksand-Regular.ttf'),
'Quicksand-Medium': require('./assets/fonts/Quicksand-Medium.ttf'),
'Quicksand-Bold': require('./assets/fonts/Quicksand-Bold.ttf'),
});
this.setState({ fontLoaded: true });
}
render() {
const MainNavigator = createStackNavigator({
Splash: { screen: Splash },
Main: { screen: Navigation },
Login: { screen: LoginScreen },
})
if (this.state.fontLoaded)
return (
<Provider store={store}>
<MainNavigator></MainNavigator>
</Provider>
)
else return null;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Splash.js
import React from 'react';
import { StyleSheet, Text, View, ImageBackground, Image, Button } from 'react-native';
import bgImage from '../../../assets/images/login-background2.png';
import logo from '../../../assets/images/app-logo.png';
import { connect } from 'react-redux';
import { checkAuth } from '../../actions/auth.actions';
class Splash extends React.Component {
static navigationOptions ={
header: null
}
constructor(props){
super(props);
this.state = {
stillLoading: true,
}
}
componentDidMount() {
this.props.checkAuth();
}
render() {
if (this.props.authState.isLoginPending)
return (
<ImageBackground source={bgImage} style={styles.backgroundContainer}>
<View style={styles.logoContainer}>
<Image source={logo} style={styles.logo}></Image>
<Text style={styles.logoText}> Welcome to HealthScout</Text>
</View>
</ImageBackground>
);
else if (this.props.authState.isLoginSuccess){
setTimeout(() => this.props.navigation.navigate('Main'));
return null;
}
else{
setTimeout(() => this.props.navigation.navigate('Login'));
return null;
}
}
}
const mapStateToProps = state => {
return {
authState: state.authState
}
}
const mapDispatchToProps = dispatch => {
return {
checkAuth: () => dispatch(checkAuth()),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Splash);
const styles = StyleSheet.create({
backgroundContainer: {
flex: 1,
alignItems: 'center',
width: null,
height: null,
justifyContent: 'center',
},
logoContainer: {
alignItems: 'center',
},
logo: {
width: 110,
height: 149,
},
logoText: {
color: '#fff',
fontSize: 40,
fontFamily: 'Quicksand',
opacity: 0.7,
marginTop: 20,
marginBottom: 10,
textAlign: 'center',
},
});
解决方案
从render
中取出createStackNavigator
。
更好的方法是在 App
class.
const MainNavigator = createStackNavigator({
Splash: { screen: Splash },
Main: { screen: Navigation },
Login: { screen: LoginScreen },
})
export default class App extends React.Component {
...
为什么?
render
是 运行 重复取决于各种条件,如改变状态、道具等。
而且您的代码看起来在 render
中使用 createStackNavigation
创建了多个组件。拿出来:)
p.s 如果您想在显示主屏幕之前等待加载字体,只需在加载字体后从初始屏幕切换到主屏幕即可。因此,更好的方法是在 SplashScreen
中加载字体并执行您想要的操作。