I would appreciate any guidance you might have regarding this topic, thank you in advance.
Here is my situation:
I have set up TaskManager to track the location of the device it is running on, which is working great. Where I am struggling is getting the data returned by TaskManager into my App component as state.
Here is a simplified example of my issue:
class App extends Component {
state = {}
// 'this' does not exist within a static method.
static updateState = (data) => this.setState(data)
render = () => { return <div>...</div> }
}
TaskManager.defineTask(LOCATION_TASK_NAME, ({ data, error }) => {
const { locations } = data // How can I get locations into state?
App.updateState(locations) // Won't work as I can't use 'this' within a static method!
})
The actual file looks like this:
import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import * as Location from 'expo-location'
import * as TaskManager from 'expo-task-manager'
import * as Permissions from 'expo-permissions'
const LOCATION_TASK_NAME = 'background-location-task'
export default class App extends React.Component {
state = {
latitude: 0,
longitude: 0,
}
static updateState(latitude, longitude) {
// updateState receives the data correctly, I just can't
// work out how to update the component state with values.
console.log(latitude, longitude)
// this.setState({ latitude, longitude }) // Doesn't work
}
notStaticUpdateState(latitude, longitude) {
// console.log(latitude, longitude) // won't work
}
async componentDidMount() {
const { status } = await Permissions.askAsync(
Permissions.LOCATION,
Permissions.USER_FACING_NOTIFICATIONS,
)
if (status === 'granted') {
await Location.startLocationUpdatesAsync(
LOCATION_TASK_NAME,
{
accuracy: Location.Accuracy.Highest,
distanceInterval: 1,
timeInterval: 1000,
},
)
}
}
render() {
const { latitude, longitude } = this.state
return (
<View style={styles.container}>
<Text>Lat: {latitude}</Text>
<Text>Lng: {longitude}</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
flex: 1,
justifyContent: 'center',
},
})
TaskManager.defineTask(LOCATION_TASK_NAME, ({ data, error }) => {
if (error) {
return
}
if (data) {
const { latitude, longitude } = data.locations[0].coords
App.updateState(latitude, longitude)
// App.notStaticUpdateState(latitude, longitude) // won't work
}
})
Related
I am using axios to fetch weather information from openweathermap api in my react application. From the result of the api call (which is a json object), I can access some properties, for example data.base. But cant access data.coord.icon or data.weather[0].id etc.
data = [
coord: { lon: -0.1257,lat: 51.5085},
weather: [{ id: 721,
main: "Haze",
description: "haze",
icon: "50n"
}],
base: "stations"
]
I tried all the possible combinations. When trying to return data.coord, got the error Objects are not valid as a React child (found: object with keys {lon, lat}). If you meant to render a collection of children, use an array instead
But data.coord.lon gives lon of undefined
import React, { Component } from 'react';
import axios from 'axios';
export class WeatherInfo extends Component {
constructor(props) {
super(props)
this.state = {
isFetching: false,
data: [],
}
}
//function to fetch weather information
async getWeatherData(lat, lon) {
const weatherApi = `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${process.env.REACT_APP_WEATHER_KEY}`
try {
this.setState({ ...this.state, isFetching: true });
const response = await axios.get(weatherApi);
this.setState({ data: response.data, isFetching: false });
console.log(response.data)
} catch (error) {
console.log(error);
this.setState({ isFetching: false })
}
}
//function to get access to users location and to call getWeatherData function
weatherInit = () => {
const success = (position) => {
this.getWeatherData(position.coords.latitude, position.coords.longitude);
}
const error = () => {
alert('Unable to retrieve location.');
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success, error);
} else {
alert('Your browser does not support location tracking, or permission is denied.');
}
}
componentDidMount() {
this.weatherInit();
}
render() {
const { data } = this.state;
return (
<div>
<p>{data.name}</p>
</div>
)
}
}
export default WeatherInfo
Here is the example of how you can display various data returned by the API.
import React, {
Component
} from 'react';
import axios from 'axios';
export class WeatherInfo extends Component {
constructor(props) {
super(props)
this.state = {
isFetching: false,
data: [],
}
}
//function to fetch weather information
async getWeatherData(lat, lon) {
const weatherApi = `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${process.env.REACT_APP_WEATHER_KEY}`
try {
this.setState({ ...this.state,
isFetching: true
});
const response = await axios.get(weatherApi);
if(response.status===200){
//update state only if status is 200
this.setState({
data: response.data,
isFetching: false
});
console.log(response.data)
}
} catch (error) {
console.log(error);
this.setState({
isFetching: false
})
}
}
//function to get access to users location and to call getWeatherData function
weatherInit = () => {
const success = (position) => {
this.getWeatherData(position.coords.latitude, position.coords.longitude);
}
const error = () => {
alert('Unable to retrieve location.');
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success, error);
} else {
alert('Your browser does not support location tracking, or permission is denied.');
}
}
componentDidMount() {
this.weatherInit();
}
render() {
const {data} = this.state;
if (data) {
return (
<div >
//display coord
<p > {data.coord.lon} < /p>
<p > {data.coord.lat} < /p>
// display weather ids
{data.weather.map(item => {
return (
< p > { item.id } < /p>) })
}
< p > { data.name } < /p> < / div >
)
}
else {
return (<div>Data is loading or Not Found</div>)}
}
}
}
export default WeatherInfo
Necessarily you need to create an JSX element for each value you want to display.
Sorry, for formatting.
I am trying when the user clicks on bottomTabNavigator the component screen will reload. I mean in my first component screen "AnotherA.js", I am using textinput which store user entered data in async storage and in another component "AnotherB.js" I am using get() of async storage to show my stored data on the screen. I am able to see the stored data the first time while reloading the whole app.
I am trying to get data without reloading, the whole app, by navigating with bottomTabNavigator it displays immediately.
//App.js
import React, { Component } from "react";
import { createAppContainer } from 'react-navigation';
import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs';
import { TabNavigator } from 'react-navigation';
import AnotherA from './AnotherA';
import AnotherB from './AnotherB';
const AppNavigator = createMaterialBottomTabNavigator(
{
AnotherA: { screen: AnotherA },
AnotherB: { screen: AnotherB }
},
{
initialRouteName: 'AnotherA',
activeColor: '#f0edf6',
inactiveColor: '#3e2465',
barStyle: { backgroundColor: '#694fad' },
pressColor: 'pink',
},
{
//tabBarComponent: createMaterialBottomTabNavigator /* or TabBarTop */,
tabBarPosition: 'bottom',
defaultnavigationOptions: ({ navigation }) => ({
tabBarOnPress: (scene, jumpToIndex) => {
console.log('onPress:', scene.route);
jumpToIndex(scene.index);
},
}),
}
);
const AppContainer = createAppContainer(AppNavigator);
export default AppContainer;
//AnotherA.js
import React, { Component } from 'react';
import { AppRegistry, AsyncStorage, View, Text, Button, TextInput, StyleSheet, Image, TouchableHighlight, Linking } from 'react-native';
import styles from './styles';
export default class AnotherA extends Component {
constructor(props) {
super(props);
this.state = {
myKey: '',
text1: '',
}
}
async getKey() {
try {
//const value = await AsyncStorage.getItem('#MySuperStore:key');
const key = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({
myKey: key,
});
} catch (error) {
console.log("Error retrieving data" + error);
}
}
async saveKey(text1) {
try {
await AsyncStorage.setItem('#MySuperStore:key', text1);
} catch (error) {
console.log("Error saving data" + error);
}
}
async resetKey() {
try {
await AsyncStorage.removeItem('#MySuperStore:key');
const value = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({
myKey: value,
});
} catch (error) {
console.log("Error resetting data" + error);
}
}
componentDidMount() {
this.getKey();
}
render() {
return (
<View style={styles.container}>
<TextInput
placeholder="Enter Data"
value={this.state.myKey}
onChangeText={(value) => this.setState({ text1: value })}
multiline={true}
/>
<Button
onPress={() => this.saveKey(this.state.text1)}
title="Save"
/>
<Button
//style={styles.formButton}
onPress={this.resetKey.bind(this)}
title="Reset"
color="#f44336"
accessibilityLabel="Reset"
/>
</View>
)
}
}
//AnotherB.js
import React, { Component } from 'react';
import { AppRegistry, AsyncStorage, View, Text, Button, TextInput, StyleSheet, Image, TouchableHighlight, Linking } from 'react-native';
import styles from './styles';
export default class AnotherB extends Component {
constructor(props) {
super(props);
this.state = {
myKey: '',
text1: '',
}
}
async getKey() {
try {
//const value = await AsyncStorage.getItem('#MySuperStore:key');
const key = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({
myKey: key,
});
} catch (error) {
console.log("Error retrieving data" + error);
}
}
componentDidMount() {
this.getKey();
}
render() {
//const { navigate } = this.props.navigation;
//const { newValue, height } = this.state;
return (
<View style={styles.container}>
<Text>{this.state.myKey}</Text>
</View>
)
}
}
Please suggest, I am new to React-Native.
The issue is that you are retrieving the value from AsyncStorage when the component mounts. Unfortunately that isn't going to load the value on the screen when you switch tabs. What you need to do is subscribe to updates to navigation lifecycle.
It is fairly straight forward to do. There are four lifecycle events that you can subscribe to. You can choose which of them that you want to subscribe to.
willFocus - the screen will focus
didFocus - the screen focused (if there was a transition, the transition completed)
willBlur - the screen will be unfocused
didBlur - the screen unfocused (if there was a transition, the transition completed)
You subscribe to the events when the component mounts and then unsubscribe from them when it unmounts. So when the event you have subscribed to happens, it will call the function that you have put into the subscriber's callback.
So you can do something like this in you AnotherB.js:
componentDidMount() {
// subscribe to the event that we want, in this case 'willFocus'
// when the screen is about to focus it will call this.getKey
this.willFocusSubscription = this.props.navigation.addListener('willFocus', this.getKey);
}
componentWillUnmount() {
// unsubscribe to the event
this.willFocusSubscription.remove();
}
getKey = async () => { // update this to an arrow function so that we can still access this, otherwise we'll get an error trying to setState.
try {
const key = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({
myKey: key,
});
} catch (error) {
console.log("Error retrieving data" + error);
}
}
Here is a quick snack that I created showing it working, https://snack.expo.io/#andypandy/navigation-life-cycle-with-asyncstorage
You can try to add then after getItem
AsyncStorage.getItem("#MySuperStore:key").then((value) => {
this.setState({
myKey: value,
});
})
.then(res => {
//do something else
});
I am new to React Native, and what i am trying to do is, that i would like to pass getUPCfromApi(upc) to ScanditSDK.js component, inside the onScan function. But i get this error see attached img.
Screenshot of error message
Api.js
import React, { Component } from 'react';
import ScanditSDK from './components/ScanditSDK'
export default class Api extends Component{
getUPCfromApi = (upc) => {
try {
let response = fetch(
`https://api.upcdatabase.org/product/${upc}/API_KEY`);
let responseJson = response.json();
return responseJson;
console.log('response',responseJson);
} catch (error) {
console.error(error);
}
}
render(){
return(
<ScanditSDK
getUPCfromApi={this.getUPCfromApi}
/>
)
}
}
ScanditSDK.js contains scanner module. Inside the onScan method i am calling getUpcFromApi(upc) which i made inside Api.js
ScanditSDK.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
findNodeHandle,
View
} from 'react-native';
import {
BarcodePicker,
ScanditModule,
ScanSession,
Barcode,
SymbologySettings,
ScanSettings
} from 'react-native-scandit';
ScanditModule.setAppKey('APIKEY');
export class ScanditSDK extends Component {
constructor(props){
super(props)
this.state = {
upc: '',
}
}
componentDidMount() {
this.scanner.startScanning();
}
render() {
return (
<View style={{
flex: 1,
flexDirection: 'column'}}>
<BarcodePicker
onScan={(session) => { this.onScan(session) }}
scanSettings= { this.settings }
ref={(scan) => { this.scanner = scan }}
style={{ flex: 1 }}/>
</View>
);
}
onScan = (session) => {
this.setState({upc:session.newlyRecognizedCodes[0].data })
alert(session.newlyRecognizedCodes[0].data + " " + session.newlyRecognizedCodes[0].symbology);
this.props.getUPCfromApi(this.state.upc)
}
}
You should use props to access your function. change your onScan function as below
onScan = (session) => {
this.setState({upc:session.newlyRecognizedCodes[0].data })
alert(session.newlyRecognizedCodes[0].data + " " + session.newlyRecognizedCodes[0].symbology);
this.props.getUPCfromApi(this.state.upc)
}
And in your Api component. Bind your function in constructor.
constructor(props){
super(props)
this.getUPCfromApi = this.getUPCfromApi.bind(this)
}
i am new in react native with ignite boilerplate. I am try to create simple function for login checking user data with API to Express. However, i am getting error: uncaught at root at takeLatest at login ReferenceError: call is not defined.
This is my code:
Api.js
// a library to wrap and simplify api calls
import apisauce from 'apisauce'
// our "constructor"
const create = (baseURL = 'http://localhost:4200/') => {
// ------
// STEP 1
// ------
//
// Create and configure an apisauce-based api object.
//
const api = apisauce.create({
// base URL is read from the "constructor"
baseURL,
// here are some default headers
headers: {
'Cache-Control': 'no-cache'
},
// 10 second timeout...
timeout: 10000
})
// ------
// STEP 2
// ------
//
// Define some functions that call the api. The goal is to provide
// a thin wrapper of the api layer providing nicer feeling functions
// rather than "get", "post" and friends.
//
// I generally don't like wrapping the output at this level because
// sometimes specific actions need to be take on `403` or `401`, etc.
//
// Since we can't hide from that, we embrace it by getting out of the
// way at this level.
//
const getRoot = () => api.get('')
const getRate = () => api.get('rate_limit')
const getUser = (username) => api.get('search/users', {q: username})
//Method for Backend-Server
//Users Methods
const getUsers = () => api.get('/users')
const login = (username, password) => api.post('users/login', {username: username, password: password})
// ------
// STEP 3
// ------
//
// Return back a collection of functions that we would consider our
// interface. Most of the time it'll be just the list of all the
// methods in step 2.
//
// Notice we're not returning back the `api` created in step 1? That's
// because it is scoped privately. This is one way to create truly
// private scoped goodies in JavaScript.
//
return {
// a list of the API functions from step 2
getRoot,
getRate,
getUser,
getUsers,
login
}
}
// let's return back our create method as the default.
export default {
create
}
LoginRedux.js:
import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'
/* ------------- Types and Action Creators ------------- */
const { Types, Creators } = createActions({
loginRequest: ['username', 'password'],
loginSuccess: ['username'],
loginFailure: ['error'],
logout: null
})
export const LoginTypes = Types
export default Creators
/* ------------- Initial State ------------- */
export const INITIAL_STATE = Immutable({
username: null,
error: null,
payload: null,
fetching: false
})
/* ------------- Reducers ------------- */
// we're attempting to login
export const request = (state) => state.merge({ fetching: true, payload: null })
// we've successfully logged in
export const success = (state, { username }) =>
state.merge({ fetching: false, error: null, username })
// we've had a problem logging in
export const failure = (state, { error }) =>
state.merge({ fetching: false, error })
// we've logged out
export const logout = (state) => INITIAL_STATE
/* ------------- Hookup Reducers To Types ------------- */
export const reducer = createReducer(INITIAL_STATE, {
[Types.LOGIN_REQUEST]: request,
[Types.LOGIN_SUCCESS]: success,
[Types.LOGIN_FAILURE]: failure,
[Types.LOGOUT]: logout
})
/* ------------- Selectors ------------- */
// Is the current user logged in?
export const isLoggedIn = (loginState) => loginState.username !== null
Redux index.js:
import { combineReducers } from 'redux'
import configureStore from './CreateStore'
import rootSaga from '../Sagas/'
export default () => {
/* ------------- Assemble The Reducers ------------- */
const rootReducer = combineReducers({
nav: require('./NavigationRedux').reducer,
github: require('./GithubRedux').reducer,
login: require('./LoginRedux').reducer,
search: require('./SearchRedux').reducer,
users: require('./UsersRedux').reducer
})
return configureStore(rootReducer, rootSaga)
}
LoginSagas.js:
import { put } from 'redux-saga/effects'
import LoginActions from '../Redux/LoginRedux'
// attempts to login
export function * login (api, { username, password }) {
const response = yield call(api.login, username, password)
if(response.ok) {
// dispatch successful logins
yield put(LoginActions.loginSuccess(username))
} else {
yield put(LoginActions.loginFailure('WRONG'))
}
// if (password === '') {
// // dispatch failure
// yield put(LoginActions.loginFailure('WRONG'))
// } else {
// // dispatch successful logins
// yield put(LoginActions.loginSuccess(username))
// }
}
index.js in Saga:
import { takeLatest, all } from 'redux-saga/effects'
import API from '../Services/Api'
import FixtureAPI from '../Services/FixtureApi'
import DebugConfig from '../Config/DebugConfig'
/* ------------- Types ------------- */
import { StartupTypes } from '../Redux/StartupRedux'
import { GithubTypes } from '../Redux/GithubRedux'
import { LoginTypes } from '../Redux/LoginRedux'
import { UsersTypes } from '../Redux/UsersRedux'
/* ------------- Sagas ------------- */
import { startup } from './StartupSagas'
import { login } from './LoginSagas'
import { getUserAvatar } from './GithubSagas'
import { getUsers } from './UsersSagas'
/* ------------- API ------------- */
// The API we use is only used from Sagas, so we create it here and pass along
// to the sagas which need it.
const api = DebugConfig.useFixtures ? FixtureAPI : API.create()
/* ------------- Connect Types To Sagas ------------- */
export default function * root () {
yield all([
// some sagas only receive an action
takeLatest(StartupTypes.STARTUP, startup),
takeLatest(LoginTypes.LOGIN_REQUEST, login, api),
// some sagas receive extra parameters in addition to an action
takeLatest(GithubTypes.USER_REQUEST, getUserAvatar, api),
takeLatest(UsersTypes.USERS_REQUEST, getUsers, api)
])
}
LoginScreen.js
import React, { PropTypes } from "react";
import { View, ScrollView, Text, TextInput, TouchableOpacity, Image, Keyboard, LayoutAnimation } from "react-native";
import { connect } from "react-redux";
import Styles from "./Styles/LoginScreenStyles";
import { Images, Metrics } from "../Themes";
import LoginActions from "../Redux/LoginRedux";
import { Button, Text as NBText, Contant, Form, Item, Input, Label } from "native-base";
import UsersActions from "../Redux/UsersRedux"
class LoginScreen extends React.Component {
static propTypes = {
dispatch: PropTypes.func,
fetching: PropTypes.bool,
attemptLogin: PropTypes.func,
getUsers: PropTypes.func
};
isAttempting = false;
keyboardDidShowListener = {};
keyboardDidHideListener = {};
constructor(props) {
super(props);
this.props.getUsers();
this.state = {
username: "reactnative#infinite.red",
password: "password",
visibleHeight: Metrics.screenHeight,
topLogo: { width: Metrics.screenWidth - 40 },
};
this.isAttempting = false;
}
componentWillReceiveProps(newProps) {
this.forceUpdate();
// Did the login attempt complete?
if (this.isAttempting && !newProps.fetching) {
this.props.navigation.goBack();
}
if(newProps.users!= null) {
console.log(newProps.users)
}
if(newProps.login != null) {
console.log("LOGIN TRY");
console.log(newProps.login);
}
if(newProps.fetching != null) {
console.log("LOGIN TRY 2");
console.log(newProps.fetching);
}
}
componentWillMount() {
// Using keyboardWillShow/Hide looks 1,000 times better, but doesn't work on Android
// TODO: Revisit this if Android begins to support - https://github.com/facebook/react-native/issues/3468
this.keyboardDidShowListener = Keyboard.addListener("keyboardDidShow", this.keyboardDidShow);
this.keyboardDidHideListener = Keyboard.addListener("keyboardDidHide", this.keyboardDidHide);
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
keyboardDidShow = e => {
// Animation types easeInEaseOut/linear/spring
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
let newSize = Metrics.screenHeight - e.endCoordinates.height;
this.setState({
visibleHeight: newSize,
topLogo: { width: 100, height: 70 },
});
};
keyboardDidHide = e => {
// Animation types easeInEaseOut/linear/spring
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.setState({
visibleHeight: Metrics.screenHeight,
topLogo: { width: Metrics.screenWidth - 40 },
});
};
handlePressLogin = () => {
// const { username, password } = this.state
// this.isAttempting = true
// attempt a login - a saga is listening to pick it up from here.
this.props.attemptLogin(this.state.username, this.state.password);
console.log("Try to login");
console.log(this.props.login);
this.props.navigation.navigate("LaunchScreen");
};
handleChangeUsername = text => {
this.setState({ username: text });
};
handleChangePassword = text => {
this.setState({ password: text });
};
render() {
const { username, password } = this.state;
const { fetching } = this.props;
const editable = !fetching;
const textInputStyle = editable ? Styles.textInput : Styles.textInputReadonly;
return (
<ScrollView
contentContainerStyle={{ justifyContent: "center" }}
style={[Styles.container, { height: this.state.visibleHeight }]}
keyboardShouldPersistTaps="always"
>
<Image source={Images.logo} style={[Styles.topLogo, this.state.topLogo]} />
<View style={Styles.form}>
<Form>
<Item stackedLabel>
<Label>Username</Label>
<Input
ref="username"
value={username}
editable={editable}
keyboardType="default"
returnKeyType="next"
autoCapitalize="none"
autoCorrect={false}
onChangeText={this.handleChangeUsername}
underlineColorAndroid="transparent"
onSubmitEditing={() => this.password._root.focus()}
/>
</Item>
<Item stackedLabel>
<Label>Password</Label>
<Input
ref={ref => (this.password = ref)}
value={password}
editable={editable}
keyboardType="default"
returnKeyType="go"
autoCapitalize="none"
autoCorrect={false}
secureTextEntry
onChangeText={this.handleChangePassword}
underlineColorAndroid="transparent"
onSubmitEditing={this.handlePressLogin}
/>
</Item>
</Form>
<View style={[Styles.loginRow]}>
<Button style={{ flex: 1, justifyContent: "center" }} full onPress={this.handlePressLogin}>
<NBText>Sign In</NBText>
</Button>
<Button
style={{ flex: 1, justifyContent: "center" }}
full
onPress={() => this.props.navigation.goBack()}
>
<NBText>Cancel</NBText>
</Button>
</View>
</View>
</ScrollView>
);
}
}
const mapStateToProps = state => {
return {
fetching: state.login.fetching,
login: state.login,
users: state.users
};
};
const mapDispatchToProps = dispatch => {
return {
attemptLogin: (username, password) => dispatch(LoginActions.loginRequest(username, password)),
getUsers: () => dispatch(UsersActions.usersRequest())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
Please help thanks.
You need to import call to use it
as import {call, put} from 'redux-saga/effects', in your LoginSagas.js
I'm new to react-native and I'm trying to use geolocation to update the state.
In componentDidMount() I can call this.setState({lat: 1}); and it works. However if I call this.setState({lat: 1}); from within the geolocation.getCurrentPosition() callback the app crashes. I'm testing on a physical device.
I have stripped back everything to isolate the problem. Any help is greatly appreciated.
Here is my code:
import React, { Component } from 'react';
import { AppRegistry,ScrollView, ListView, Text, View } from 'react-native';
class TestProject extends Component {
constructor(props) {
super(props);
this.state = {
lat: 0
};
}
componentDidMount() {
navigator.geolocation.getCurrentPosition(function(position) {
this.setState({lat: 1}); // this causes a crash - without this line the app does not crash.
},
(error) => alert(error.message)
);
this.setState({lat: 1}); // this works
}
render() {
return (
<View>
<Text>
{this.state.lat}
</Text>
</View>
);
}
}
AppRegistry.registerComponent('TestProject', () => TestProject);
Thanks to #Phil I just had to set self = this:
let self = this;
navigator.geolocation.getCurrentPosition(function(position) { self.setState({ lat: 1 }); }, (error) => alert(error.message) );