реагировать на собственную навигацию - компонентDidMount () запускается дважды - PullRequest
0 голосов
/ 18 сентября 2018

Я новичок в React Native.Я пытаюсь создать приложение, которое имеет экран Splash, который впоследствии перешел бы на экран Login, если пользователь не прошел проверку подлинности, или экран Main, если пользователь прошел проверку подлинности.Это делается с помощью this.props.navigation.navigate() Проблема в том, что компонент Splash будет смонтирован дважды.Я проверил это, напечатав внутри componentDidMount() из Splash.Из-за этого дважды появляется экран входа в систему / главный экран, что выглядит очень неприятно.Есть ли способ это исправить?Также я хочу добавить некоторую задержку, когда экран меняется с 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',
  },
});

1 Ответ

0 голосов
/ 18 сентября 2018

Решение

Возьмите createStackNavigator из render. Лучше всего оборачивать экраны выше App класса.

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

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

Почему?

render выполняется несколько раз в зависимости от различных условий, таких как изменение состояния, реквизит и т. Д.
И ваш код выглядит, создавая несколько компонентов с createStackNavigation в render. Вынь :)

p.s Если вы хотите дождаться загрузки шрифтов, прежде чем показывать домашний экран, просто перейдите на домашний экран с заставки после загруженных шрифтов. Таким образом, лучший способ - загрузить шрифты в SplashScreen и делать то, что вы хотите.

...