I am developing in react-native v0.63 and Expo SDK 38. My goal is to read the camera roll off of an android or ios phone and select pictures then story those pictures into an array and display them on the mobile screen. I have found through research that the react-native cameraroll is not supported in Expo SDK 38 and have to use expo-media-library for those functions. As a test I pulled some code from researching which asks for permissions to access the camera and cameraroll. that goes ok. Then I call this.camera.takePictureAsync() to see if I can access the camera to take a picture. simple test. that is where I get the error: Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_this.camera.takePictureAsync')
here is my setup: The full error is:
WARNING
18:17
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_this.camera.takePictureAsync')]
Stack trace:
node_modules\react-navigation\node_modules\@react-navigation\native\lib\module\createNavigationAwareScrollable.js:105:6 in NavigationAwareScrollable#render
node_modules\regenerator-runtime\runtime.js:45:36 in tryCatch
node_modules\regenerator-runtime\runtime.js:274:29 in invoke
node_modules\regenerator-runtime\runtime.js:45:36 in tryCatch
node_modules\regenerator-runtime\runtime.js:135:27 in invoke
node_modules\regenerator-runtime\runtime.js:170:16 in PromiseImpl$argument_0
node_modules\promise\setimmediate\core.js:45:6 in tryCallTwo
node_modules\promise\setimmediate\core.js:200:22 in doResolve
node_modules\promise\setimmediate\core.js:66:11 in Promise
node_modules\regenerator-runtime\runtime.js:169:15 in callInvokeWithMethodAndArg
node_modules\regenerator-runtime\runtime.js:192:38 in enqueue
node_modules\regenerator-runtime\runtime.js:219:8 in exports.async
http://192.168.0.27:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&minify=false&hot=false:253923:41 in _callee
http://192.168.0.27:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&minify=false&hot=false:254521:108 in onPress
node_modules\react-native\Libraries\Components\Touchable\TouchableNativeFeedback.js:169:10 in Pressability$argument_0.onPress
node_modules\react-native\Libraries\Pressability\Pressability.js:655:17 in _performTransitionSideEffects
node_modules\react-native\Libraries\Pressability\Pressability.js:589:6 in _receiveSignal
node_modules\react-native\Libraries\Pressability\Pressability.js:499:8 in responderEventHandlers.onResponderRelease
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:286:4 in invokeGuardedCallbackImpl
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:497:2 in invokeGuardedCallback
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:521:2 in invokeGuardedCallbackAndCatchFirstError
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:683:41 in executeDispatch
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:707:19 in executeDispatchesInOrder
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:872:28 in executeDispatchesAndRelease
[native code]:null in forEach
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:851:4 in forEachAccumulated
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:897:20 in runEventsInBatch
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:1069:18 in runExtractedPluginEventsInBatch
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2835:35 in batchedUpdates$argument_0
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:20569:13 in batchedUpdates$1
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2731:29 in batchedUpdates
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2834:16 in _receiveRootNodeIDEvent
node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2911:27 in receiveTouches
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:425:19 in __callFunction
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:112:6 in __guard$argument_0
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:373:10 in __guard
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:111:4 in callFunctionReturnFlushedQueue
[native code]:null in callFunctionReturnFlushedQueue
...
my imports:
import React, { Component } from "react";
import styles from "./styles";
import { Platform, Image, ImageBackground, TextInput, TouchableWithoutFeedback, TouchableOpacity, Dimensions, FlatList, SafeAreaView,TouchableHighlight, View as RNView, Text, Alert } from "react-native";
import {Container, Grid, Col, Row, Header, Content, Item, Input, View, List, ListItem, Textarea, Button, Form, Accordion, Left, Right, Body,Thumbnail, Icon, Title, Spinner, Picker, DatePicker, } from 'native-base';
import { Ionicons } from '@expo/vector-icons';
import { FlatGrid } from 'react-native-super-grid';
import {Image as SVGImage} from "react-native-svg";
import Fire from '../Fire';
import firebase from 'firebase';
import * as ImagePicker from 'expo-image-picker';
// import * as Permissions from 'expo-permissions';
import Expo, { Constants, } from 'expo';
import * as MediaLibrary from 'expo-media-library';
import * as Permissions from 'expo-permissions';
import { Camera } from 'expo-camera';
to get permissions I call:
async componentDidMount() {
this.getCameraPermissions();
}
async getCameraPermissions() {
console.log('getCameraPermissions: enter function');
const { status } = await Permissions.askAsync(Permissions.CAMERA);
if (status === 'granted') {
console.log("getCameraPermissions: status = "+status);
this.setState({ cameraGranted: true });
} else {
this.setState({ cameraGranted: false });
console.log('Uh oh! The user has not granted us permission.');
}
this.getCameraRollPermissions();
}
async getCameraRollPermissions() {
console.log("getCameraRollPermissions: Enter Function");
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (status === 'granted') {
console.log("getCameraRollPermissions: status = "+status);
this.setState({ rollGranted: true });
} else {
console.log('Uh oh! The user has not granted us permission.');
this.setState({ rollGranted: false });
}
}
This is the function call that throws the error. you can see by the console logs it gets into the function and dies on the takepictureasync()
takePictureAndCreateAlbum = async () => {
console.log('takePictureCreateAlbum: Entering function');
const { uri } = await this.camera.takePictureAsync()
.then(() => {
Alert.alert('takePictureCreateAlbum: taking picture')
})
.catch(error => {
Alert.alert('takePictureCreateAlbum Error!');
});
console.log('takePictureCreateAlbum: uri', uri);
const asset = await MediaLibrary.createAssetAsync(uri);
console.log('asset', asset);
MediaLibrary.createAlbumAsync('Expo', asset)
.then(() => {
Alert.alert('Album created!')
})
.catch(error => {
Alert.alert('An Error Occurred!')
});
};
as a test I call it from a button here:
<Button
style={{flex: 1, justifyContent: "flex-start", backgroundColor: "lightgrey", marginRight: 5}}
onPress={() =>
this.state.rollGranted && this.state.cameraGranted
? this.takePictureAndCreateAlbum()
: Alert.alert('Permissions not granted')
// this.switchToStories();
}
>
I am testing on an emulated android device and a real android device Samsung S7. both produce the error.
I thought I could trap the error but failed. I also tried returning all values from the call not just the uri and it acted the same. thoughts?
Ok, I hope this helps others that fall into this trap. This error boils down to really understanding the .then .catch error handling.I needed to perform any functions on the uri within the .then()
a great short article that got me going can be read here: https://medium.com/@lucymarmitchell/using-then-catch-finally-to-handle-errors-in-javascript-promises-6de92bce3afc
also I was calling camera function wrong:
const { uri } = await this.camera.takePictureAsync()
.then(() => {
Alert.alert('takePictureCreateAlbum: taking picture')
})
.catch(error => {
Alert.alert('takePictureCreateAlbum Error!');
});
needed the this removed from this.camera.takePictureAsync().