I am creating an app which uses the phone's location. I would like to be able to get the latitude and longitude and using it as part of an api address.
I have been following this sample code using react-native-get-location and have been able to print the information in json formate but can't pull the latitude and longitude and use them.
react-native-get-location
Here is my code.
import GetLocation from 'react-native-get-location'
export default class App extends React.Component {
constructor (props) {
super(props);
this.state = {
isLoading: true,
latitude: null,
longitude: null,
location: null
};
}
_requestLocation = () => {
GetLocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 150000,
})
.then(location => {
this.setState ({
location,
isLoading: false,
});
})
.catch(error => {
const { code, message} = error;
if (code === 'CANCELLED') {
Alert.alert('location cancelled by user or by another request');
}
if (code === 'UNAVAILABLE') {
Alert.alert('Location service is disabled or unavailable');
}
if (code === 'TIMEOUT') {
Alert.alert('Location request timed out');
}
if (code === 'UNAUTHORIZED') {
Alert.alert('Authorization denied')
}
this.setState({
location: null,
isLoading: false,
});
});
}
componentDidMount() {
GetLocation.getCurrentPosition(async (info) => {
const location = await GetLocation(
info.coords.latitude,
info.coords.longitude
);
})
const fetch = require('node-fetch');
fetch('https://api.weatherapi.com/v1/forecast.json?&q=London', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
}).then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson,
})
}).catch((error) => {
console.error(error);
});
}
render() {
const {location, isLoading} = this.state;
if (this.state.isLoading) {
return (
<View style={{flex: 1, paddingTop: 20}}>
<ActivityIndicator />
</View>
);
}
return (
<View style={{flex:1, paddingTop: 20}}>
<Text>{JSON.stringify(location, 0, 2)}</Text>
<View style={{flex:1, flexDirection: 'row', textAlign: 'center', paddingLeft: 90}}>
<Button
disabled={isLoading}
title="Get Location"
onPress={this._requestLocation}
/>
</View>
</View>
)
}
}
Use expo-location instead of react-native-get-location as it is very easy to implement.
Here is the working app: Expo Snack
Screenshot:
import React, { useEffect, useState } from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
let apiKey = 'YOUR_API_KEY';
import * as Location from 'expo-location';
export default function App() {
const [location, setLocation] = useState(null);
const [errorMsg, setErrorMsg] = useState(null);
const [address, setAddress] = useState(null);
// const [getLocation, setGetLocation] = useState(false);
const getLocation = () => {
(async () => {
let { status } = await Location.requestPermissionsAsync();
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied');
}
Location.setGoogleApiKey(apiKey);
console.log(status);
let { coords } = await Location.getCurrentPositionAsync();
setLocation(coords);
console.log(coords);
if (coords) {
let { longitude, latitude } = coords;
let regionName = await Location.reverseGeocodeAsync({
longitude,
latitude,
});
setAddress(regionName[0]);
console.log(regionName, 'nothing');
}
// console.log();
})();
};
return (
<View style={styles.container}>
<Text style={styles.big}>
{!location
? 'Waiting'
: `Lat: ${location.latitude} \nLong: ${
location.longitude
} \n${JSON.stringify(address?.['subregion'])}`}
</Text>
<TouchableOpacity onPress={getLocation}>
<View
style={{
height: 100,
backgroundColor: 'teal',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
marginTop: 20,
}}>
<Text style={styles.btnText}> GET LOCATION </Text>
</View>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
},
big: {
fontSize: 18,
color: 'black',
fontWeight: 'bold',
},
btnText: {
fontWeight: 'bold',
fontSize: 25,
color: 'white',
},
});
react-native-geolocation-service is a good alternative too for fetching latitude & longitude values.
Example usage:
import GeoLocation from 'react-native-geolocation-service';
const getDeviceCurrentLocation = async () => {
return new Promise((resolve, reject) =>
GeoLocation.getCurrentPosition(
(position) => {
resolve(position);
},
(error) => {
reject(error);
},
{
enableHighAccuracy: true, // Whether to use high accuracy mode or not
timeout: 15000, // Request timeout
maximumAge: 10000 // How long previous location will be cached
}
)
);
};
Related
I am using redux persist with asyncstorage save items in a bookmarks list. The items are in a flatlist and when I click on one item, it navigates me to another screen. I would like to implement the functional bookmark in the header of that screen.
When I tried doing this, and clicked the bookmark in the header, and go back to the bookmarks, it just shows a blank card. It looks like it is not updating the state properly. How can I fix this?
StackNavigator.tsx
const MainStackNavigator = () => {
const { books, bookmarks } = useAppSelector((state) => state.booksReducer);
const dispatch = useDispatch();
const fetchBooks = () => dispatch(getBooks());
const addToBookmarkList = (book) => dispatch(addBookmark(book));
const removeFromBookmarkList = (book) => dispatch(removeBookmark(book));
useEffect(() => {
fetchBooks();
}, []);
const handleAddBookmark = (book) => {
addToBookmarkList(book);
};
const handleRemoveBookmark = (book) => {
removeFromBookmarkList(book);
};
const handleSwapBookmark = (book) => {
removeFromBookmarkList(book);
};
const RenderItem = () => {
const ifExists = (book) => {
if (bookmarks.filter((item) => item.id === book.id).length > 0) {
return true;
}
return false;
};
return (
<TouchableOpacity
onPress={() =>
ifExists(i) ? handleRemoveBookmark(i) : handleAddBookmark(i)
}
activeOpacity={0.7}
style={{
flexDirection: "row",
padding: 2,
backgroundColor: ifExists(i) ? "#F96D41" : "#2D3038",
borderRadius: 20,
alignItems: "center",
justifyContent: "center",
height: 40,
width: 40,
}}
>
<MaterialCommunityIcons
color={ifExists(i) ? "white" : "#64676D"}
size={24}
name={ifExists(i) ? "bookmark-outline" : "bookmark"}
/>
</TouchableOpacity>
);
};
return (
<AppStack.Navigator>
<AppStack.Screen
name="BookmarksScreen"
component={BookmarksScreen}
options={{
title: "Search",
statusBarColor: isDarkMode ? "white" : "black",
headerLargeTitle: true,
headerTranslucent: true,
headerLargeTitleHideShadow: true,
}}
/>
<AppStack.Screen
name="Screen2"
component={Screen2}
options={({ route }) => ({
headerLargeTitle: false,
title: route.params.name,
headerTranslucent: true,
headerRight: () => <RenderItem item={route.params.name} />,
})}
/>
</AppStack.Navigator>
);
};
actions.js
import axios from "axios";
import { BASE_URL } from "../config";
// Define action types
export const GET_BOOKS = "GET_BOOKS";
export const ADD_TO_BOOKMARK_LIST = "ADD_TO_BOOKMARK_LIST";
export const REMOVE_FROM_BOOKMARK_LIST = "REMOVE_FROM_BOOKMARK_LIST";
export const SWAP_IN_BOOKMARK_LIST = "SWAP_IN_BOOKMARK_LIST";
export const getBooks = () => {
try {
return async (dispatch) => {
const response = await axios.get(`${BASE_URL}`);
if (response.data) {
dispatch({
type: GET_BOOKS,
payload: response.data,
});
} else {
console.log("Unable to fetch data from the API BASE URL!");
}
};
} catch (error) {
console.log(error);
}
};
export const addBookmark = (book) => (dispatch) => {
dispatch({
type: ADD_TO_BOOKMARK_LIST,
payload: book,
});
};
export const removeBookmark = (book) => (dispatch) => {
dispatch({
type: REMOVE_FROM_BOOKMARK_LIST,
payload: book,
});
};
hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
reducers.ts
import {
GET_BOOKS,
ADD_TO_BOOKMARK_LIST,
REMOVE_FROM_BOOKMARK_LIST,
} from "./actions";
const initialState = {
books: [],
bookmarks: [],
};
function booksReducer(state = initialState, action) {
switch (action.type) {
case GET_BOOKS:
return { ...state, books: action.payload };
case ADD_TO_BOOKMARK_LIST:
return { ...state, bookmarks: [...state.bookmarks, action.payload] };
case REMOVE_FROM_BOOKMARK_LIST:
return {
...state,
bookmarks: state.bookmarks.filter(
(book) => book.id !== action.payload.id
),
};
default:
return state;
}
}
export default booksReducer;
store.ts
import { createStore, combineReducers, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import AsyncStorage from "#react-native-async-storage/async-storage";
import { persistStore, persistReducer } from "redux-persist";
import booksReducer from "./reducers";
const persistConfig = {
key: "root",
storage: AsyncStorage,
whitelist: ["bookmarks"],
};
const rootReducer = combineReducers({
booksReducer: persistReducer(persistConfig, booksReducer),
});
export const store = createStore(rootReducer, applyMiddleware(thunk));
export const persistor = persistStore(store);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
BookmarksScreen.tsx
const BookmarksScreen = () => {
return (
<View>
<FlatList
data={bookmarks}
keyExtractor={(item) => item.id}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
/>
</View>
);
}
renderItem
const renderItem = ({ item }) => {
return (
<TouchableOpacity
onPress={() =>
navigation.navigate("Screen2", {name: item.name})}
>
<View style={{ flexDirection: "row", flex: 1 }}>
<View>
<Text
style={{
fontSize: 22,
paddingRight: 16,
color: "black",
fontFamily: "Medium",
left: 45,
top: 6,
}}
>
{item.country}
</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
};
I think you forgot to access props that's the reason booked-marked not working i change some code please check it's working or not.
StackNavigator.tsx
const RenderItem = (item) => {
const ifExists = (book) => {
if (bookmarks.filter((item) => item.id === book.id).length > 0) {
return true;
}
return false;
};
return (
<TouchableOpacity
onPress={() =>
ifExists(item) ? handleRemoveBookmark(item) : handleAddBookmark(item)
}
activeOpacity={0.7}
style={{
flexDirection: "row",
padding: 2,
backgroundColor: ifExists(i) ? "#F96D41" : "#2D3038",
borderRadius: 20,
alignItems: "center",
justifyContent: "center",
height: 40,
width: 40,
}}
>
<MaterialCommunityIcons
color={ifExists(i) ? "white" : "#64676D"}
size={24}
name={ifExists(i) ? "bookmark-outline" : "bookmark"}
/>
</TouchableOpacity>
);
};
I have to React Native IOS App with Login Screen for users. In the store auth, I am getting string output from Login API as 'success' or 'Login Failed'.I want to transfer this login status to Login Screen, to tell the user about the wrong credentials. Below is the auth store:
auth.js:
export const LOGIN ='LOGIN';
export const login=(textemailid,textpassword) =>{
const formData = new FormData();
formData.append('txtUemail',textemailid);
formData.append('txtUpass',textpassword);
return async dispatch =>{
await fetch('https:/-------------------/login.php',
{
method:'post',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: formData
})
.then(res => res.text())
.then(
(loginresult) =>{
var login = loginresult.replace('\r\n\r\n\r\n\t\r\n\t\r\n\t','');
console.log('loginstatus is '+login);
}).catch(err =>{
console.log(err);
})
dispatch({type:LOGIN,loginStatus:login});
}
}
I want to transfer the 'login' value to Login Screen using navigation. Below is the LoginScreen code:
LoginScreen.js:
import React,{useEffect} from 'react';
import { ActivityIndicator,StyleSheet, Text, View
,KeyboardAvoidingView,TouchableOpacity,Image} from "react-native";
import { Button } from 'react-native-elements';
import { ScrollView } from "react-native-gesture-handler";
import { HelperText,TextInput } from 'react-native-paper';
import { useDispatch } from 'react-redux';
import * as authActions from '../../store/actions/auth';
import Icon from 'react-native-vector-icons/FontAwesome5';
import AsyncStorage from '#react-native-async-storage/async-
storage'
import Toast from 'react-native-root-toast';
const LoginScreen = ({route}) => {
const [textemailid, setTextEmailId] = React.useState('');
const [textpassword, setTextPassword] = React.useState('');
const [isLoading,setIsLoading] = React.useState(false);
const [error, setError] = React.useState('');
const dispatch = useDispatch();
const loginStatus1 = useSelector(state =>
state?.auth?.login_Status); **getting login_Status from auth reducer**
//console.log(state);
console.log('login status is '+loginStatus1)
const loginHandler = async () => {
let action
action = authActions.login(
textemailid,
textpassword
);
setError(null);
setIsLoading(true);
try{
dispatch(action);
console.log('login status is '+loginStatus);
if(loginStatus === 'Login Failed'){
let toast_success = Toast.show('Wrong Credentials');
setIsLoading(false);
}
else if(loginStatus === 'success'){
props.navigation.navigate({routeName:'Home'});
}
} catch(err){
setError(err.message);
console.log(err.message);
setIsLoading(false);
}
};
return(
<KeyboardAvoidingView style={styles.container}>
<ScrollView>
<View style={styles.container}>
<View style={styles.subView}>
<Image
style={{flex:1, height: 100, width: 100,alignSelf:'center',bottom:350}}
source={require('../../assets/profile1.png')}
resizeMode="contain"
/>
<View style={styles.welcometextview}>
<Text style={styles.welcometext}>Welcome!</Text>
{/* <Loader loading={isLoading} color="#ff66be" title='Loading'/> */}
</View>
<View style={styles.textinputemailview}>
<TextInput
underlineColor='grey'
style={styles.textinputemail}
label='Email'
keyboardType="email-address"
editable={true}
autoCapitalize = 'none'
value={textemailid}
theme={{ colors: { placeholder: "#f5f5f5", background: "transparent", text:
'green', primary: '#D43790' } }}
onChangeText={textemailid=>setTextEmailId(textemailid)}>
</TextInput>
</View>
<View style={styles.textinputpasswordview} >
<TextInput style={styles.textinputpassword}
underlineColor='grey'
label='Password'
autoCapitalize = 'none'
editable={true}
value={textpassword}
onChangeText={textpassword => setTextPassword(textpassword)}
theme={{ colors: { placeholder: "#f5f5f5", background: "transparent",text:
'green',primary: '#D43790' } }}>
</TextInput>
</View>
<View style={styles.loginbuttonview}>
{isLoading ? (
<ActivityIndicator size='small' color='green'/>
) :
(
<Button buttonStyle={{
backgroundColor: "#EB4207"
}}
containerStyle={{
marginTop: 12,
width: "50%"
}}
onPress={
() => { loginHandler();
}}
title='Log in'/>
)}
</View>
</View>
<TouchableOpacity style={styles.textforgotpasswordview} onPress=.
{()=>props.navigation.navigate('ForgotPasswordPage')}>
<Text style={styles.textforgotpassword}>Forgot your password?</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.textregisterview} onPress=.
{()=>props.navigation.navigate('SignUp')} >
<Text style={styles.textregister}>Not a member?Sign up now</Text>
</TouchableOpacity>
</View>
</ScrollView>
</KeyboardAvoidingView>
)}
const styles = StyleSheet.create({
container: {
backgroundColor: '#0B0B45',
flex:1,
},
subView: {
backgroundColor: '#1D1F33',
height: 750,
marginTop: 150,
borderTopRightRadius: 40,
borderTopLeftRadius: 40,
},
welcometextview:{
bottom:'80%',
justifyContent:'center',
alignItems:'center'
},
welcometext:{
fontWeight:'bold',
color:'grey',
fontSize:20,
},
textinputemailview:{
position:'absolute',
top:'23%',
width:'80%',
alignSelf:'center'
},
textinputemail:{
backgroundColor:'transparent',
fontWeight:'bold',
fontSize:20,
},
textinputpasswordview:{
position:'absolute',
top:'35%',
width:'80%',
alignSelf:"center"
},
textinputpassword:{
backgroundColor:'transparent',
fontWeight:'bold',
fontSize:20,
},
textregisterview:{
position:'absolute',
top:'75%',
alignSelf:'center'
},
textregister:{
color: "#EB4207",
fontSize: 20,
fontWeight: "bold",
textDecorationLine: 'underline'
},
textforgotpasswordview:{
position:'absolute',
alignSelf:'center',
bottom:'33%'
},
textforgotpassword:{
color: "white",
fontSize: 20,
fontWeight: "bold",
},
loginbuttonview:{
bottom:'45%',
justifyContent:'center',
alignItems:'center'
},
});
export default LoginScreen;
Below is the auth reducer:
auth.js:
import { GETDEVICEINFO, LOGIN,LOGOUT } from '../actions/auth';
const initialState = {
mobileno: null,
login_Status:null,
availableDevice:[],
};
export default (state = initialState,action) => {
switch(action.type){
case LOGIN:
return {
login_Status : action.loginStatus
};
case GETDEVICEINFO:
return {
availableDevice:action.devices
}
case LOGOUT:
return initialState;
default: return state;
}
}
I don't think async storage will work here because I don't want to persist data but only want to get data from auth store and also using AsyncStorage will not flush old data, it stores data till u logout and login.
After running the above code, I am getting the whole function as below:
login status is function login(textemailid, textpassword) {
var formData = new FormData();
formData.append('txtUemail', textemailid);
formData.append('txtUpass', textpassword);
return function _callee(dispatch) {
return _regenerator.default.async(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return _regenerator.default.awrap(fetch('https:--------
-/login.php', {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: formData
}).then(function (res) {
return res.text();
}).then(function (loginresult) {
var login =
loginresult.replace('\r\n\r\n\r\n\t\r\n\t\r\n\t', '');
console.log('login1 is ' + login);
saveDataToStoragelogin(login, textemailid);
}).catch(function (err) {
console.log(err);
}));
case 2:
dispatch({
type: LOGIN,
loginStatus: login
});
case 3:
case "end":
return _context.stop();
}
}
}, null, null, null, Promise);
};
Can anyone say how to get only login_Status string. Thanks in Advance?
I would try to change
try{
props.navigation.navigate('LoginScreen', {
paramKey: login,
})
to
try{
navigation.navigate('LoginScreen', {
paramKey: login,
})
No need to pass navigation prop to auth store. When you dispatch({type:LOGIN}) with payload store that state in reducer.Get the State using UseSelector.
For example you are in Screen A and did login Api call and store api response data in reducer. In same screen use useSelector to get the api data response from reducer. based on response type navigate to respected screens. Don't place api call in reducers.
Please check this example https://github.com/raduungurean/react-native-redux-auth-login-logout-example
Need some help running through my codes to make WebRTC work. I am just trying to make a call from one device to the other. Realise I'm not throughly understanding WebRTC. My app crashes when the answer is emitted back.
The socket/emitter I am working with is actually
FeathersJS services. It is serving as my backend, whenever I need to emit, I send a create service and in my backend, feathersJS emit a customEmitter ['offer' 'answer' 'ice-candidate']. Although I am able to receive all emitted events, I am unable to get WebRTC to work. The below are my React-native code:
import React, { useContext, useEffect, useState } from 'react';
import {
View, SafeAreaView, Button, StyleSheet,
} from 'react-native';
import {
RTCPeerConnection,
RTCSessionDescription,
RTCView,
mediaDevices,
} from 'react-native-webrtc';
import ContextApp from '../../context/contextApp';
import FeathersApp, { Services } from '../../Feathers';
const styles = StyleSheet.create({
container: {
backgroundColor: '#313131',
justifyContent: 'space-between',
alignItems: 'center',
height: '100%',
},
text: {
fontSize: 30,
},
rtcview: {
justifyContent: 'center',
alignItems: 'center',
height: '40%',
width: '80%',
backgroundColor: 'black',
},
rtc: {
width: '80%',
height: '100%',
},
toggleButtons: {
width: '100%',
flexDirection: 'row',
justifyContent: 'space-around',
},
});
const VideoCallPage = ( props: any ) => {
const { userId } = props;
const { authState } = useContext(ContextApp);
const callService = FeathersApp.service(Services.CALL);
const [callAlert, setCallAlert] = useState<boolean>(false);
const [offerData, setOfferData] = useState<any>();
const configuration = {"iceServers": [{"url": "stun:stun.l.google.com:19302"}]};
const localPC = new RTCPeerConnection(configuration);
const [localStream, setLocalStream] = useState<any>();
const [remoteStream, setRemoteStream] = useState<any>();
const sendToPeer = (messageType: any, payload: any) => {
callService.create({
callType: messageType,
sdp: payload,
caller: authState._id,
answerer: userId,
candidate: payload,
})
}
const createOffer = async () => {
const offer = await localPC.createOffer();
await localPC.setLocalDescription(offer).then(() => console.log('local offer succeeded'));
sendToPeer('offer', localPC.localDescription);
}
const createIceCandidate = () => {
localPC.onicecandidate = e => {
try {
console.log('localPC icecandidate:', e.candidate);
if (e.candidate) {
sendToPeer('ice-candidate', e.candidate)
}
} catch (err) {
console.error(`Error adding remotePC iceCandidate: ${err}`);
}
};
}
const startCall = async () => {
console.log('start call funtion')
const newStream = await mediaDevices.getUserMedia({
audio: true,
video: false,
});
setLocalStream(newStream);
createIceCandidate()
createOffer();
};
const recieveCall = async (incoming: any) => {
console.log('accepting call');
await localPC.setRemoteDescription(new RTCSessionDescription(incoming.sdp));
const answer = await localPC.createAnswer();
await localPC.setLocalDescription(answer).then(() => console.log('localPC desc succeeded'));
sendToPeer('answer', localPC.localDescription);
createIceCandidate();
localPC.addStream(localStream);
localPC.onaddstream = e => {
console.log('remotePC tracking with ', e);
if (e.stream && remoteStream !== e.stream) {
console.log('RemotePC received the stream', e.stream);
setRemoteStream(e.stream);
}
};
};
const recieveAnswer = (payload: any) => {
console.log('recieved answer: ', payload.candidate.sdp)
localPC.setRemoteDescription(new RTCSessionDescription(payload.candidate.sdp));
localPC.onaddstream = e => {
if (e.stream && remoteStream !== e.stream) {
console.log('RemotePC received the stream', e.stream);
setRemoteStream(e.stream);
}
};
}
// alert for any calls
useEffect(() => {
callService.on('ice-candidate', (incoming: any) => {
localPC.addIceCandidate(incoming.data.sdp);
localPC.addStream(localStream);
});
callService.on('offer', async (payload: any) => {
if (payload.data.answerer === authState._id) {
const newStreamForReciever = await mediaDevices.getUserMedia({
audio: true,
video: false,
});
setLocalStream(newStreamForReciever);
setOfferData(await payload.data);
setCallAlert(true);
}
});
callService.on('answer', async (payload: any) => {
if (payload.data.answerer === authState._id) {
console.log(userId, 'answered')
recieveAnswer(await payload.data);
}
});
// return (() => {
// callService.removeAllListener('ice-candidate');
// callService.removeAllListener('offer');
// callService.removeAllListener('answer');
// })
}, [callService]);
return (
<SafeAreaView style={styles.container}>
{!localStream && <Button title="Click to start CALL stream" onPress={startCall} />}
{callAlert && <Button title="Answer Call" onPress={() => recieveCall(offerData)} />}
{localStream && (
<View style={styles.toggleButtons}>
</View>
)}
<View style={styles.rtcview}>
{localStream && <RTCView style={styles.rtc} streamURL={localStream.toURL()} />}
</View>
<View style={styles.rtcview}>
{remoteStream && <RTCView style={styles.rtc} streamURL={remoteStream.toURL()} />}
</View>
</SafeAreaView>
)
};
export default VideoCallPage;
What is it that I am missing out??
Any guidance you can provide is greatly appreciated!
This may sound duplicated, but it's not.
I'm kinda newbie in React-Native.
I'm trying to write an MQTT-Client app, making use of "react-native-paho-mqtt" library, which should be able to connect to my own broker with this uri: tcp://217.218.171.92:1883
but apparently the uri must be started with "wss" only!!!
How can I make my app use tcp:// ?
above that, is it possible??
here is my App.js:
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TouchableHighlight,
TextInput,
Button
} from 'react-native';
import { Client, Message } from 'react-native-paho-mqtt';
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' +
'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
export default class App extends Component<{}> {
constructor(){
super();
const myStorage = {
setItem: (key, item) => {
myStorage[key] = item;
},
getItem: (key) => myStorage[key],
removeItem: (key) => {
delete myStorage[key];
},
};
const client = new Client({ uri: "wss://m12.cloudmqtt.com:31839/", clientId: 'clientIdReactNative' + (new Date()).getTime(), storage: myStorage });
client.on('messageReceived', (entry) => {
console.log(entry);
this.setState({message: [...this.state.message, entry.payloadString]});
});
client.on('connectionLost', (responseObject) => {
if (responseObject.errorCode !== 0) {
console.log(responseObject.errorMessage);
this.setState({error: 'Lost Connection', isConnected: false});
}
});
this.connect(client)
.then(() => {
console.log('connect!');
this.setState({isConnected: true, error: ''})
})
.catch((error)=> {
console.log(error);
});
this.state = {
client,
message: [''],
messageToSend:'',
isConnected: false
}
}
connect(client){
return client.connect({
useSSL: true,
userName: 'azebvdny',
password: 'MsULac9Uhig0'
})
.then(() => {
client.subscribe('S/ReactMQTT');
})
}
onConnect = () => {
const { client } = this.state;
client.subscribe('ReactMQTT');
this.pushText('connected');
};
pushText = entry => {
const { message } = this.state;
this.setState({ message: [...message, entry] });
};
onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
}
}
onMessageArrived(message) {
console.log("onMessageArrived:"+message.payloadString);
}
componentWillMount(){
}
sendMessage(){
var message = new Message(this.state.messageToSend);
message.destinationName = "S/ReactMQTT";
if(this.state.isConnected){
this.state.client.send(message);
}else{
this.connect(this.state.client)
.then(() => {
console.log('connect!');
this.state.client.send(message);
this.setState({error: '', isConnected: true});
})
.catch((error)=> {
console.log(error);
this.setState({error: error});
});
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Nativess!
</Text>
<Text style={styles.instructions}>
Message: {this.state.message.join(' --- ')}
</Text>
<Text style={{color: 'red'}}>
{this.state.error}
</Text>
{ this.state.isConnected ?
<Text style={{color: 'green'}}>
Connected
</Text> : null
}
<TextInput
value={this.state.messageToSend}
onChangeText={(value => this.setState({messageToSend: value}))}
placeholder="Type here... "
style={styles.input} />
<Button onPress={this.sendMessage.bind(this)} title="Send Message" />
</View>
);
}
}
const styles = StyleSheet.create({
...
});
Any help would be greatly appreciated.
react-native-paho-mqtt only supports WebSocket.
because react-native-paho-mqtt doesn't support raw TCP out of the box
If you use real-native-tcp to configure the client, it may be possible on the code.
The example of a module tells us it's not possible.
test('should fail to create a new client with an invalid ws uri', function () {
let client = null;
let error;
try {
client = new Client({ uri: 'http://example.com', clientId: 'testclientid', webSocket, storage });
} catch (err) {
error = err;
}
expect(client).toBe(null);
expect(error).not.toBe(null);
For new googlers: you can use react_native_mqt.
After you managed to properly install the library, for example, this could be your App.js:
import React, { Component } from 'react';
import init from 'react_native_mqtt';
import { AsyncStorage,
StyleSheet,
Text,
View,
TextInput,
Button,
Alert
} from 'react-native';
init({
size: 10000,
storageBackend: AsyncStorage,
defaultExpires: 1000 * 3600 * 24,
enableCache: true,
sync: {},
});
export default class App extends Component {
constructor(){
super();
this.onMessageArrived = this.onMessageArrived.bind(this)
this.onConnectionLost = this.onConnectionLost.bind(this)
const client = new Paho.MQTT.Client('yourURL', yourPort, 'someClientID',);
client.onMessageArrived = this.onMessageArrived;
client.onConnectionLost = this.onConnectionLost;
client.connect({
onSuccess: this.onConnect,
useSSL: false ,
userName: 'yourUser',
password: 'yourPass',
onFailure: (e) => {console.log("here is the error" , e); }
});
this.state = {
message: [''],
client,
messageToSend:'',
isConnected: false,
};
}
onMessageArrived(entry) {
console.log("onMessageArrived:"+message.payloadString);
this.setState({message: [...this.state.message, entry.payloadString]});
}
onConnect = () => {
const { client } = this.state;
console.log("Connected!!!!");
client.subscribe('hello/world');
this.setState({isConnected: true, error: ''})
};
sendMessage(){
message = new Paho.MQTT.Message(this.state.messageToSend);
message.destinationName = "hello/world";
if(this.state.isConnected){
this.state.client.send(message);
}else{
this.connect(this.state.client)
.then(() => {
this.state.client.send(message);
this.setState({error: '', isConnected: true});
})
.catch((error)=> {
console.log(error);
this.setState({error: error});
});
}
}
onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
this.setState({error: 'Lost Connection', isConnected: false});
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native MQTT!
</Text>
<Text style={styles.instructions}>
Message: {this.state.message.join(' --- ')}
</Text>
<Text style={{color: 'red'}}>
{this.state.error}
</Text>
{ this.state.isConnected ?
<Text style={{color: 'green'}}>
Connected
</Text> : null
}
<TextInput
value={this.state.messageToSend}
onChangeText={(value => this.setState({messageToSend: value}))}
placeholder="Type hereee..."
style={styles.input} />
<Button onPress={this.sendMessage.bind(this) } title="Send Message" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
button: {
padding: 10,
alignItems: 'center',
justifyContent: 'center',
},
buttonLabel: {
color: 'blue',
},
input:{
width: 300
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
Replace the URL and other stuff with your own. For example, you have to put it like this:
const client = new Paho.MQTT.Client('something.something.ir', 1883, '123456');
When pressing the Button nothing happens. The picture shows a warning and I can get rid of that if I change the
onPress={this._onSearchPressed}
to
onPress={() => this._onSearchPressed()}
But now when pressing the Button i get the error you see on the picture below like "undefined is not a function..".
How do I call a onPress correctly?
'use strict';
import React, { Component } from 'react';
import {
StyleSheet,
Text,
TextInput,
View,
Button,
ActivityIndicator,
Image,
} from 'react-native';
type Props = {};
function urlForQueryAndPage(key, value, pageNumber) {
const data = {
country: 'uk',
pretty: '1',
encoding: 'json',
listing_type: 'buy',
action: 'search_listings',
page: pageNumber,
};
data[key] = value;
const querystring = Object.keys(data)
.map(key => key + '=' + encodeURIComponent(data[key]))
.join('&');
return 'https://api.nestoria.co.uk/api?' + querystring;
}
export default class SearchPage extends Component<Props> {
static navigationOptions = {
title: 'Property Finder',
};
constructor(props) {
super(props);
this.state = {
searchString: 'london',
isLoading: false,
};
}
_onSearchTextChanged = (event) => {console.log('_onSearchTextChanged');
this.setState({ searchString: event.nativeEvent.text });
console.log('Current: '+this.state.searchString+', Next: '+event.nativeEvent.text);
_executeQuery = (query) => {
console.log(query);
this.setState({ isLoading: true });
};
_onSearchPressed = () => {
const query = urlForQueryAndPage('place_name', this.state.searchString, 1);
this._executeQuery(query);
};
};
render() {
console.log('SearchPage.render');
const spinner = this.state.isLoading ? <ActivityIndicator size='large'/> : null;
return (
<View style={styles.container}>
<Text style={styles.description}>
Search for houses to buy!
</Text>
<Text style={styles.description}>
Search by place-name or postcode.
</Text>
<View style={styles.flowRight}>
<TextInput
underlineColorAndroid={'transparent'}
style={styles.searchInput}
value={this.state.searchString}
onChange={this._onSearchTextChanged}
placeholder='Search via name or postcode'/>
<Button
onPress={this._onSearchPressed}
color='#48BBEC'
title='Go'>
</Button>
</View>
<Image source={require('./Resources/house.png')} style={styles.image}/>
{spinner}
</View>
);
}
}
const styles = StyleSheet.create({
description: {
marginBottom: 20,
fontSize: 18,
textAlign: 'center',
color: '#a56565'
},
flowRight: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'stretch',
},
searchInput: {
height: 36,
padding: 4,
marginRight: 5,
flexGrow: 1,
fontSize: 18,
borderWidth: 1,
borderColor: '#48BBEC',
borderRadius: 8,
color: '#48BBEC',
},
container: {
padding: 30,
marginTop: 65,
alignItems: 'center'
},
image: {
width: 217,
height: 138,
},
});
Okay, I think I might have found the error.
Here inside your code
_onSearchTextChanged = (event) => {console.log('_onSearchTextChanged');
this.setState({ searchString: event.nativeEvent.text });
console.log('Current: '+this.state.searchString+', Next: '+event.nativeEvent.text);
_executeQuery = (query) => {
console.log(query);
this.setState({ isLoading: true });
};
_onSearchPressed = () => {
const query = urlForQueryAndPage('place_name', this.state.searchString, 1);
this._executeQuery(query);
};
};
You are nesting these two functions
_executeQuery = (query) => {
console.log(query);
this.setState({ isLoading: true });
};
_onSearchPressed = () => {
const query = urlForQueryAndPage('place_name', this.state.searchString, 1);
this._executeQuery(query);
};
inside your _onSearchTextChanged function. You probably might want to do something like this
_onSearchTextChanged = (event) => {console.log('_onSearchTextChanged');
this.setState({ searchString: event.nativeEvent.text });
console.log('Current: '+this.state.searchString+', Next: '+event.nativeEvent.text);
}
_executeQuery = (query) => {
console.log(query);
this.setState({ isLoading: true });
};
_onSearchPressed = () => {
const query = urlForQueryAndPage('place_name', this.state.searchString, 1);
this._executeQuery(query);
};
Notice the closing } of your first function