我有一个带有非组件类(不会扩展Component或React.Component)的React Native应用程序,该类处理WebSocket(生产者和使用者)连接。我将此WebSocket实例化为一个单例,并在各处使用。我遇到的麻烦是如何从此非组件类访问“应用程序导航”或“ StackNavigator状态”?这是为了打开一个全局模式以显示传入的数据。
基于不同的想法,对以下任意一项的回答都可以解决问题:
OR
OR
任何更简单的方法都值得赞赏。因为这是我唯一想在全局范围内做某事的情况,所以我宁愿不使用任何其他状态管理工具/库。
我的 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>
);
答案 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')
我无法测试,但应该可以