如何在屏幕外使用反应导航

时间:2019-04-22 01:12:32

标签: javascript react-native react-navigation react-native-ios

输入正确的代码后,我想使我的应用程序移至下一页,但是这样做一直很麻烦。我正在使用文件名AccessForm.js进行操作,该文件不是屏幕,而是访问代码屏幕中包含的组件。我尝试使用this.props.navigation.navigate('CreateAccountScreen');,但遇到错误“未定义不是对象(评估'this.props.navigation')。经过反复试验,我发现我只能在内部使用react-navigation出于某种怪异的原因而创建了一个实际的屏幕。此后,我尝试使用this.statethis.setState({})来跟踪屏幕变量,并将其同步到实际的访问代码屏幕,以便我可以使用导航。不幸的是,this.setState还会引发“未定义不是对象”错误。我在下面粘贴了我的代码的缩写版本。在屏幕文件问题之外实现这种导航的最佳方法是什么? / p>

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

3 个答案:

答案 0 :(得分:1)

道具中应该有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);

编辑: checkCode方法不属于您的LoginForm。您需要:
1.使其成为LoginForm的一部分。
2.请记住使用bindarrow function定义。否则,未定义您的this内部函数。

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

您可以在https://medium.com/shoutem/react-to-bind-or-not-to-bind-7bf58327e22a处了解有关bind或箭头方法的更多信息

答案 1 :(得分:1)

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>
    );
  }
}

答案 2 :(得分:0)

从以下位置复制并粘贴(参考):https://github.com/react-navigation/react-navigation/issues/1439#issuecomment-303661539

它对我有效。

您可以将顶级导航器引用传递给服务,并从该服务调度操作。

// App.js

import NavigatorService from './services/navigator';

const Navigator = StackNavigator({ /* ... */ })

class App extends Component {
  // ...

  render(): {
    return (
      <Navigator
        ref={navigatorRef => {
          NavigatorService.setContainer(navigatorRef);
        }}
      />
    );
  }
}
// services/navigator.js
// @flow

import { NavigationActions } from 'react-navigation';
import type { NavigationParams, NavigationRoute } from 'react-navigation';

let _container; // eslint-disable-line

function setContainer(container: Object) {
  _container = container;
}

function reset(routeName: string, params?: NavigationParams) {
  _container.dispatch(
    NavigationActions.reset({
      index: 0,
      actions: [
        NavigationActions.navigate({
          type: 'Navigation/NAVIGATE',
          routeName,
          params,
        }),
      ],
    }),
  );
}

function navigate(routeName: string, params?: NavigationParams) {
  _container.dispatch(
    NavigationActions.navigate({
      type: 'Navigation/NAVIGATE',
      routeName,
      params,
    }),
  );
}

function navigateDeep(actions: { routeName: string, params?: NavigationParams }[]) {
  _container.dispatch(
    actions.reduceRight(
      (prevAction, action): any =>
        NavigationActions.navigate({
          type: 'Navigation/NAVIGATE',
          routeName: action.routeName,
          params: action.params,
          action: prevAction,
        }),
      undefined,
    ),
  );
}

function getCurrentRoute(): NavigationRoute | null {
  if (!_container || !_container.state.nav) {
    return null;
  }

  return _container.state.nav.routes[_container.state.nav.index] || null;
}

export default {
  setContainer,
  navigateDeep,
  navigate,
  reset,
  getCurrentRoute,
};

然后您可以在任何地方使用Navigator服务。

赞:

import NavigatorService from './services/navigator';

NavigatorService.navigate('Home');