0

I was just trying to start learning React-Native and Expo-Go for the past few days. I was simply trying to access some camera, basically just want to start with a MainPage then navigate to the CameraPage that can scan an item, but got some Render Error:

ERROR [TypeError: Invalid attempt to destructure non-iterable instance.In order to be iterable, non-array objects must have a Symbol.iterator method.]

I am working on a window setup with an Expo-Go in my iphone. I think the problem might be from my expo-camera version. Really new to this so if there are any better approach to this, I'm free for any suggestion.

├── @expo/[email protected]
├── @react-navigation/[email protected]
├── @react-navigation/[email protected]
├── @react-navigation/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]

MainPage

import { createNativeStackNavigator } from '@react-navigation/native-stack';
import React, { useState, useEffect } from 'react';
import { View, Text, Button } from 'react-native';
import { Camera } from 'expo-camera';

import HomeScreen from './HomeScreen';
import DetailsScreen from './DetailsScreen';
import SettingsScreen from './SettingsScreen';
import CameraScreen from './CameraScreen';

export type RootStackParamList = {
  Home: undefined;
  Details: undefined;
  Settings: undefined;
  Camera: undefined;
};

const Stack = createNativeStackNavigator<RootStackParamList>();

export default function PermissionsScreen({ onGranted }: { onGranted?: () => void }) {
  const [status, setStatus] = useState<'undetermined' | 'granted' | 'denied' | null>(null);

  useEffect(() => {
  Camera.getCameraPermissionsAsync().then(res => {
    setStatus(res.granted ? 'granted' : 'denied');
    if (res.granted && onGranted) onGranted();
  });
}, []);

  const ask = async () => {
    const res = await Camera.requestCameraPermissionsAsync();
    setStatus(res.granted ? 'granted' : 'denied');
    if (res.granted && onGranted) onGranted(); // ✅ only call if defined
  };

  if (status === 'undetermined' || status === null) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Checking camera permissions …</Text>
    </View>
  );
}

if (status === 'denied') {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Need camera permission</Text>
      <Button title="Grant Permission" onPress={ask} />
    </View>
  );
}

return (
  <Stack.Navigator initialRouteName="Home">
    <Stack.Screen
      name="Home"
      component={HomeScreen}
      options={({ navigation }) => ({
        title: 'Home',
        headerRight: () => (
          <View style={{ flexDirection: 'row' }}>
            <Button
              title="Settings"
              onPress={() => navigation.navigate('Settings')}
            />
            <Button
              title="Camera"
              onPress={() => navigation.navigate('Camera')}
            />
          </View>
        ),
      })}
    />
    <Stack.Screen name="Details" component={DetailsScreen} />
    <Stack.Screen name="Settings" component={SettingsScreen} />
    <Stack.Screen name="Camera" component={CameraScreen} />
  </Stack.Navigator>
)

CameraPage

  const toggleCameraFacing = () => {
    setFacing(current => (current === 'back' ? 'front' : 'back'));
  };

  return (
    <View style={styles.container}>
      <Camera style={styles.camera} type={facing} />
      <View style={styles.buttonContainer}>
        <TouchableOpacity style={styles.button} onPress={toggleCameraFacing}>
          <Text style={styles.text}>Flip Camera</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center' },
  message: { textAlign: 'center', paddingBottom: 10 },
  camera: { flex: 1 },
  buttonContainer: {
    position: 'absolute',
    bottom: 64,
    flexDirection: 'row',
    backgroundColor: 'transparent',
    width: '100%',
    paddingHorizontal: 64,
  },
  button: { flex: 1, alignItems: 'center' },
  text: { fontSize: 24, fontWeight: 'bold', color: 'white' },
});
New contributor
Andaman Jamprasitsakul is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1
  • 2
    "I think the problem might be from my expo-camera version." - What led you to this conclusion? It's not useful to just guess what the causes to issues are, do a little bit of digging to see what additional details you can uncover. You have an error message, is there not any error stacktrace accompanying it that would inform you exactly where the issue is thrown and let you see what led up to that point or at least give you a starting point for any investigation? Please edit and try to provide more details that could help readers better understand what you are asking. Commented Nov 16 at 18:18

1 Answer 1

0

The expo-camera library works better in a development build and native setup, but also try using useRef instead of useState,because most of these errors come from bad state loading or lag of state loading that usually comes with useState, however useRef resolves these issues (Pro tip: If you use VS Code, and have the Github Copilot Extension enabled, you can use that (GPT 4.1 Preferred) to change all of the useState to useRef (do a backup before though, it messes up sometimes))

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.