react-redux - react native 导航 - componentDidMount() 触发两次

标签 react-redux react-native react-native-navigation

我是 React Native 新手。我正在尝试构建一个具有 Splash 屏幕的应用程序,如果用户尚未经过身份验证或 Main ,该应用程序稍后会导航到 Login 屏幕如果用户已通过身份验证,则显示屏幕。这是使用 this.props.navigation.navigate() 完成的 问题是 Splash 组件将被安装两次。我通过在 SplashcomponentDidMount() 内部打印来检查这一点。因此,登录/主屏幕会进入两次,看起来非常不愉快。有没有什么办法解决这一问题? 另外,我想在屏幕从 Splash 更改为 LoginMain 时使用 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 类之上包装屏幕的更好方法。

const MainNavigator = createStackNavigator({
  Splash: { screen: Splash },
  Main: { screen: Navigation },
  Login: { screen: LoginScreen },
})

export default class App extends React.Component {
...

为什么?

render 重复运行取决于各种条件,如更改状态、 Prop 等。
您的代码看起来在 render 中使用 createStackNavigation 制作多个组件。拿出来:)

p.s 如果您想在显示主屏幕之前等待加载字体,只需在加载字体后从启动屏幕切换到主屏幕即可。因此,更好的方法是在 SplashScreen 中加载字体并执行您想要的操作。

关于react-redux - react native 导航 - componentDidMount() 触发两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52382275/

相关文章:

javascript - 使用 Connect 进行 mapStateToProps 和 mapDispatchToProps 时对 redux : still getting empty object for this. props 使用react

javascript - 如何在分派(dispatch)到 reducer 之前从操作中调用函数?

javascript - 在 redux store 中处理 "selected"项的正确方法

android - React Native 中默认的样式单位是什么?

react-native - TextInput onFocus 和 onBlur.React-Native 时改变样式

react-native - 如何在 React Native 中直接打开应用的位置权限设置

javascript - react native react 导航(v6): How to set presentation options on each screen

javascript - 异步功能后强制 React 组件更新?

javascript - React Native 响应式屏幕

javascript - 在 React Native Navigation V2 中添加 Tab 导航