Как использовать реагирующую навигацию за пределами экрана - PullRequest
2 голосов
/ 22 апреля 2019

Я бы хотел, чтобы мое приложение переместилось на следующую страницу, когда код введен правильно, но у меня были большие проблемы с этим. Я работаю в файле с именами AccessForm.js, который не является экраном, но является компонентом, который включен в экран кода доступа. Я попытался использовать this.props.navigation.navigate('CreateAccountScreen');, но натолкнулся на ошибку «Undefined не является объектом (оценивая this.props.navigation»). С некоторыми пробами и ошибками я обнаружил, что могу использовать реагирующую навигацию только внутри фактической по какой-то странной причине. После этого я попытался использовать this.state и this.setState({}), чтобы отслеживать переменную экрана и синхронизировать ее с реальным экраном кода доступа, чтобы я мог использовать навигацию. К сожалению, this.setState также выдает ошибку «Не определено, но не объект». Я вставил сокращенную версию своего кода ниже. Каков наилучший способ добиться этой навигации за пределами проблемы файла экрана?

App.js ---->

import { createStackNavigator, createAppContainer } from 'react-navigation';

import AccessScreen from './src/screens/AccessScreen';
import CreateAccountScreen from './src/screens/CreateAccountScreen';

const RootStack = createStackNavigator ({
    EnterAccessCode : {
        screen: AccessScreen
    },
    CreateAccount : {
        screen: CreateAccountScreen
    }
},
{
  headerMode: 'none'
});

const App = createAppContainer(RootStack);

export default App;

AccessForm.js ---->

import React from 'react';
import { StyleSheet, Text, View, TextInput, AlertIOS } from 'react-native';


var firebase = require("firebase");

if (!firebase.apps.length) { // Don't open more than one firebase session
  firebase.initializeApp({ // Initialize firebase connection
    apiKey: "key",
    authDomain: "domain",
    databaseURL: "url",
    storageBucket: "storage_bucket",
  });
}

this.codesRef = firebase.database().ref('codes'); // A reference to the codes section in the db

// this.state = {
//   screen: 0
// };

export default class LoginForm extends React.Component {
  constructor(props) {
    super(props);
    //this.checkCode = this.checkCode.bind(this); // throws error
  }
  render() {
    return (
      <View style={styles.container} >
        <TextInput
            style={styles.input}
            placeholder='Access Code'
            returnKeyType='go'
            onSubmitEditing={(text) => checkCode(text.nativeEvent.text)} // Checks the code entered
            autoCapitalize='none'
            autoCorrect={false}
        />
      </View>
    );
  }
}


function checkCode(text) {
  var code = text; // Set entered code to the var "code"
  var identifier = ""; // Used to store unique code object identifier
  codesRef.once('value', function(db_snapshot) {
    let codeIsFound = false
    db_snapshot.forEach(function(code_snapshot) { // Cycle through available codes in db
      if (code == code_snapshot.val().value) { // Compare code to db code
        codeIsFound = true;
        identifier = code_snapshot.key; // Code object ID
      }
    })
    if (codeIsFound) {
      deleteCode(identifier); // Delete the code if used, maybe do this after account is created?
      this.props.navigation.navigate('CreateAccountScreen');
      //this.setState({screen: 1}); // this throws error
      // MOVE TO NEXT SCREEN
      //this.props.navigation.navigate('AccountCreateScreen'); // throws error
    } else { // wrong code
      // note to self : add error message based on state var
      AlertIOS.alert("We're Sorry...", "The code you entered was not found in the database! Please contact Mr. Gibson for further assistance.");
    }
  });
}

function deleteCode(id) { // delete a code from unique ID
  firebase.database().ref('codes/' + id).remove();
}

// stylesheet is below

Login.js ---->

import React from 'react';
import { StyleSheet, Text, View, Image, TextInput, KeyboardAvoidingView, Platform } from 'react-native';
import AccessForm from './AccessForm';

export default class App extends React.Component {
  render() {
    return (
        <View>
            <View style={styles.logoContainer}>
                <Image 
                    source={require('../images/mhs.jpg')}
                    style={styles.logo}
                />
                <Text style={styles.app_title}>MHS-Protect</Text>
                <Text>An app to keep MHS safe and in-touch.</Text>
            </View>
            <KeyboardAvoidingView style={styles.container} behavior='padding'>
              <View style ={styles.formContainer}>
                  <AccessForm/>
              </View>
            </KeyboardAvoidingView>
        </View>
    );
  }
}

//styles below

Ответы [ 2 ]

1 голос
/ 22 апреля 2019

import React from 'react';
import { StyleSheet, Text, View, TextInput, AlertIOS } from 'react-native';

var firebase = require('firebase');

if (!firebase.apps.length) {
  // Don't open more than one firebase session
  firebase.initializeApp({
    // Initialize firebase connection
    apiKey: 'key',
    authDomain: 'domain',
    databaseURL: 'url',
    storageBucket: 'storage_bucket',
  });
}

export default class LoginForm extends React.Component {
  constructor(props) {
    super(props);
    this.codesRef = firebase.database().ref('codes'); // A reference to the codes section in the db
  }

  checkCode = text => {
    var code = text; // Set entered code to the var "code"
    var identifier = ''; // Used to store unique code object identifier
    this.codesRef.once('value', function(db_snapshot) {
      let codeIsFound = false;
      db_snapshot.forEach(function(code_snapshot) {
        // Cycle through available codes in db
        if (code == code_snapshot.val().value) {
          // Compare code to db code
          codeIsFound = true;
          identifier = code_snapshot.key; // Code object ID
        }
      });
      if (codeIsFound) {
        this.deleteCode(identifier); // Delete the code if used, maybe do this after account is created?
        this.props.navigation.navigate('CreateAccount');
      } else {
        // wrong code
        // note to self : add error message based on state var
        AlertIOS.alert(
          "We're Sorry...",
          'The code you entered was not found in the database! Please contact Mr. Gibson for further assistance.'
        );
      }
    });
  };

  deleteCode = id => {
    firebase
      .database()
      .ref('codes/' + id)
      .remove();
  };

  render() {
    return (
      <View style={styles.container}>
        <TextInput
          style={styles.input}
          placeholder="Access Code"
          returnKeyType="go"
          onSubmitEditing={text => this.checkCode(text.nativeEvent.text)} // Checks the code entered
          autoCapitalize="none"
          autoCorrect={false}
        />
      </View>
    );
  }
}
1 голос
/ 22 апреля 2019

Вы должны иметь navigation объект в вашем реквизите. По умолчанию реагирующая навигация передает navigation на все экраны, кроме других компонентов. Для этого у вас есть два варианта:
1. Передайте navigation реквизиты со своего экрана всем дочерним компонентам (не рекомендуется).
2. Используйте withNavigation как упоминание в документе здесь https://reactnavigation.org/docs/en/connecting-navigation-prop.html

import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';

class MyBackButton extends React.Component {
  render() {
    return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />;
  }
}

// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);

Edit: Метод checkCode не принадлежит вашему LoginForm. Вам необходимо:
1. Сделайте это частью LoginForm.
2. Не забудьте использовать определение bind или arrow function. В противном случае ваша this внутренняя функция не определена.

import { withNavigation } from 'react-navigation';
class LoginForm extends React.Component {
    checkCode = (text) => {
        ....
    };
}
export default withNavigation(LoginForm);

Подробнее о bind или методе стрелок можно прочитать здесь https://medium.com/shoutem/react-to-bind-or-not-to-bind-7bf58327e22a

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...