从非组件类访问应用程序导航或堆栈导航器的状态

时间:2020-10-07 11:40:56

标签: react-native

我有一个带有非组件类(不会扩展Component或React.Component)的React Native应用程序,该类处理WebSocket(生产者和使用者)连接。我将此WebSocket实例化为一个单例,并在各处使用。我遇到的麻烦是如何从此非组件类访问“应用程序导航”或“ StackNavigator状态”?这是为了打开一个全局模式以显示传入的数据。

基于不同的想法,对以下任意一项的回答都可以解决问题:

  1. 如何从非组件类访问应用程序的导航,以便能够进行navigation.navigate?

OR

  1. 如何从非组件类访问堆栈导航器的状态(显示基于布尔状态的模式)?

OR

  1. 如何在要从非组件类访问的全局变量中存储组件的导航(或状态)?

任何更简单的方法都值得赞赏。因为这是我唯一想在全局范围内做某事的情况,所以我宁愿不使用任何其他状态管理工具/库。

我的 WebSocket.js 类似于:

import ReconnectingWebSocket from 'react-native-reconnecting-websocket';
import base64 from 'react-native-base64';

let instance = null;
const BROKER_SERVICE_URL = '192.168.43.111';

class WebSockets {
    if (!instance) {
      instance = this;
    }
    this.getNowAsDateTime = () => {
      let now = new Date();
      return (
        now.getUTCFullYear() +
        ('0' + (now.getUTCMonth() + 1)).slice(-2) +
        ('0' + now.getUTCDate()).slice(-2) +
        ('0' + now.getUTCHours()).slice(-2) +
        ('0' + now.getUTCMinutes()).slice(-2) +
        ('0' + now.getUTCSeconds()).slice(-2)
      );
    };
    
    // A property for testing the singleton
    this.creationDateTime = this.getNowAsDateTime();
    
    this.producer = new ReconnectingWebSocket(
      'ws://' +
        BROKER_SERVICE_URL +
        ':8080/ws/v2/producer/persistent/public/default/' +
        'mesosphere-router-input?compressionType=ZLIB',
      null,
      {
        reconnectInterval: 1000,
        maxReconnectInterval: 10000,
        reconnectDecay: 3,
        timeoutInterval: 5000,
        maxReconnectAttempts: null,
      },
    );
    let producerHeartCheck = {
      timeout: 55000, //default 10s
      timeoutObj: null,
      serverTimeoutObj: null,
      reset: function () {
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
      },
      start: function () {
        // eslint-disable-next-line consistent-this
        let self = this;
        this.timeoutObj = setTimeout(function () {
          console.log(
            'PRODUCER SOCKET',
            SEPARATOR,
            'producerHeartCheck.reset().start() SENDING pingRequest \n',
          );
          let jsonToSend = JSON.stringify({
            pingRequest: {
              workerId: 1,
              status: global.presence,
              requestedOn: instance.getNowAsDateTime(),
            },
          });
          instance.producer.send(
            JSON.stringify({
              payload: base64.encode(jsonToSend),
            }),
          );
          self.serverTimeoutObj = setTimeout(function () {
            instance.producer.close();
          }, self.timeout);
        }, this.timeout);
      },
    };
    this.producer.onopen = (event) => {
      producerHeartCheck.reset().start();
    };
    this.producer.onmessage = (event) => {
      producerHeartCheck.reset().start();
    };
    this.producer.onerror = (event) => {
      this.producer.close();
    };
    this.producer.onclose = (event) => {
      this.producer.reconnect();
    };
    
    this.consumer = new ReconnectingWebSocket(
      'ws://' +
        BROKER_SERVICE_URL +
        ':8080/ws/v2/consumer/persistent/public/default/' +
        'worker-1/WorkerId-' +
        this.getNowAsDateTime() +
        '?subscriptionType=Exclusive&consumerName=userID-' +
        this.getNowAsDateTime() +
        '',
      null,
      {
        reconnectInterval: 1000,
        maxReconnectInterval: 10000,
        reconnectDecay: 3,
        timeoutInterval: 5000,
        maxReconnectAttempts: null,
      },
    );
    let consumerHeartCheck = {
      timeout: 60000, //default 10s
      timeoutObj: null,
      serverTimeoutObj: null,
      reset: function () {
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
      },
      start: function () {
        // eslint-disable-next-line consistent-this
        let self = this;
        this.timeoutObj = setTimeout(function () {
          // Do nothing?
          self.serverTimeoutObj = setTimeout(function () {
            instance.consumer.close();
          }, self.timeout);
        }, this.timeout);
      },
    };
    this.consumer.onopen = (event) => {
      consumerHeartCheck.reset().start();
    };
    this.consumer.onmessage = (event) => {
      consumerHeartCheck.reset().start();
      const MESSAGE = JSON.parse(event.data);
      const MESSAGE_ID = MESSAGE.messageId;
      const MESSAGE_BODY = base64.decode(MESSAGE.payload);
      // Get MESSAGE_BODY as JSON
      const messageAsJson = JSON.parse(MESSAGE_BODY);

      // THIS IS WHERE I WANT TO SHOW THE MESSAGE BODY IN THE MODAL 
      // THIS IS WHERE I WANT TO SHOW THE MESSAGE BODY IN THE MODAL 
      // THIS IS WHERE I WANT TO SHOW THE MESSAGE BODY IN THE MODAL 

      // Send acknowledgement for the received message
      this.consumer.send(
        JSON.stringify({
          messageId: MESSAGE_ID,
        }),
      );
    };
    this.consumer.onerror = (event) => {
      this.consumer.close();
    };
    this.consumer.onclose = (event) => {
      this.consumer.reconnect();
    };
    return instance;
}

export default WebSockets;

这是我的 Navigation.js ,其中包含要显示的模型:

import React, {useState} from 'react';
import {
  Image,
  Linking,
  SafeAreaView,
  ScrollView,
  Text,
  TouchableHighlight,
  View,
} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {
  createDrawerNavigator,
  DrawerItem,
  DrawerItemList,
} from '@react-navigation/drawer';
import styles from './styles/navigation-styles';
import AboutScreen from './screens/AboutScreen';
import HomeScreen from './screens/HomeScreen';
import Login from './screens/Login';
import NotificationsScreen from './screens/NotificationsScreen';
import Signup from './screens/Signup';
import UserDetailsScreen from './screens/UserDetailsScreen';
import Modal from './Modal';

const DrawerMenu = (props) => (
  <SafeAreaView style={styles.drawerMenuSafeAreaView}>
    <TouchableHighlight
      onPress={() => props.navigation.navigate('User Details')}>
      <View style={styles.drawerMenuView}>
        <Image
          source={require('./images/user.png')}
          style={styles.drawerMenuImage}
        />
        <View style={styles.drawerMenuText}>
          <Text style={styles.drawerName}>Name</Text>
          <Text style={styles.drawerMobileNumber}>0123456789</Text>
        </View>
      </View>
    </TouchableHighlight>
    <ScrollView>
      <DrawerItemList {...props} />
      <DrawerItem
        label="Google"
        onPress={() => Linking.openURL('https://google.com')}
      />
    </ScrollView>
  </SafeAreaView>
);
const Drawer = createDrawerNavigator();

function LeftDrawer() {
  return (
    <Drawer.Navigator
      initialRouteName="Home"
      drawerBackgroundColor="grey"
      drawerPosition="left"
      drawerWidth="250"
      drawerType="slide"
      drawerContentOptions={{
        activeTintColor: 'red',
        inactiveTintColor: 'black',
        activeBackgroundColor: 'white',
      }}
      drawerContent={(navigation) => <DrawerMenu {...navigation} />}>
      <Drawer.Screen
        name="Home"
        component={HomeScreen}
        options={{
          drawerIcon: ({tintColor}) => (
            <Image
              source={require('./icons/home.png')}
              style={[styles.icon, {tintColor: tintColor}]}
            />
          ),
        }}
      />
      <Drawer.Screen
        name="About"
        component={AboutScreen}
        options={{
          drawerIcon: ({tintColor}) => (
            <Image
              source={require('./icons/about.png')}
              style={[styles.icon, {tintColor: tintColor}]}
            />
          ),
        }}
      />
      <Drawer.Screen
        name="Logout"
        component={Login}
        options={{
          drawerIcon: ({tintColor}) => (
            <Image
              source={require('./icons/logout.png')}
              style={[styles.icon, {tintColor: tintColor}]}
            />
          ),
        }}
      />
    </Drawer.Navigator>
  );
}

const Stack = createStackNavigator();

const MainStack = (props) => {
  return (
    <Stack.Navigator
      initialRouteName="Home">
      <Stack.Screen
        name="OfferModal"
        component={Modal}
        options={{
          headerShown: false,
          animationEnabled: true,
        }}
      />
      <Stack.Screen
        name="SignUp"
        component={Signup}
        options={{
          headerShown: false,
        }}
      />
      <Stack.Screen
        name="Login"
        component={Login}
        options={{
          headerShown: false,
        }}
      />
      <Stack.Screen
        name="User Details"
        component={UserDetailsScreen}
        options={{
          headerTitle: 'User Details',
        }}
      />
      <Stack.Screen
        name="Home"
        component={LeftDrawer}
        options={{
          headerShown: false,
        }}
      />
      <Stack.Screen
        name="Notifications"
        component={NotificationsScreen}
        options={{
          headerTitle: 'Notifications',
        }}
      />
    </Stack.Navigator>
  );
};

function AppContainer() {
  return (
    <NavigationContainer>
      <MainStack />
    </NavigationContainer>
  );
}

export default AppContainer;

我的 Modal.js 是:

import React from 'react';
import {View, Text, TouchableOpacity} from 'react-native';

export default ({navigation}) => (
  <View
    style={{
      flex: 1,
      backgroundColor: 'transparent',
      alignItems: 'center',
      justifyContent: 'center',
    }}>
    <TouchableOpacity
      style={{backgroundColor: 'white', padding: 20}}
      onPress={() => navigation.navigate('Home')}>
      <Text>Let's go to HOME</Text>
    </TouchableOpacity>
  </View>
);

1 个答案:

答案 0 :(得分:0)

其中一种方法可能如下。

内部WebSocket.js创建一个接受导航属性的函数,并将其保存到例如类中

this.navigation = navigation => {
 if(!navigation) return this.navigation;
 this.navigation = navigation ;
}

在您的Stack屏幕之一中,导入WebSocket类,并在useEffect或componentDidMount中设置导航

useEffect(()=>{
  ...
  WebSocket.navigation(props.navigation);
},[])

...

componentDidMount(){
  ...
  WebSocket.navigation(this.props.navigation);
}

现在,您的WebSocket类具有导航实例,从那里您应该能够在任何WebSocket函数内部进行导航

this.navigation()?.navigate('my-modal')

我无法测试,但应该可以