Because of Google Play, I had to update an old project of mine to the latest expo versions (version 43.0.0 to be exact). The idea is for the app to scan a QRCode and process the data, simply. However, expo-barcode-scanner only works once and after that I need to close and open the app again to work. Has anyone encountered this problem and (or) knows how to solve it? Below is my code:
{escaneando ? (
<BarCodeScanner
barCodeTypes={[
BarCodeScanner.Constants.BarCodeType.ean13,
BarCodeScanner.Constants.BarCodeType.ean8,
BarCodeScanner.Constants.BarCodeType.upc_a,
BarCodeScanner.Constants.BarCodeType.upc_e,
]}
onBarCodeScanned={this.handleBarCode.bind(this)}
style={[StyleSheet.absoluteFillObject, styles.barscan]}
/>
) : null}
And library specifications:
"@react-native-community/masked-view": "^0.1.11",
"@react-native-community/netinfo": "^6.0.5",
"@react-navigation/native": "^6.0.6",
"@react-navigation/stack": "^6.0.11",
"expo": "~43.0.0",
"expo-av": "^10.1.3",
"expo-barcode-scanner": "^11.1.2",
"expo-status-bar": "~1.1.0",
"lodash": "^4.17.21",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "^0.64.2",
"react-native-dropdownalert": "^4.3.0",
"react-native-elements": "^3.4.2",
"react-native-gesture-handler": "^1.10.3",
"react-native-in-app-notification": "^3.2.0",
"react-native-offline": "^6.0.0",
"react-native-paper": "^4.10.0",
"react-native-reanimated": "^2.2.3",
"react-native-safe-area-context": "^3.3.2",
"react-native-screens": "^3.9.0",
"react-native-web": "0.17.1",
"react-navigation": "^4.4.4",
"react-redux": "^7.2.6",
"redux": "^4.1.2",
"redux-thunk": "^2.4.0",
"reselect": "^4.1.2"
with expo-camera
it works perfectly.
1)- install expo-camera
: expo install expo-camera
this is the code for it :
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { Camera } from 'expo-camera';
const QrcodeReader = ({navigation}) => {
const [hasPermission, setHasPermission] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
useEffect(() => {
(async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return(
<View style={styles.container}>
<Camera
onBarCodeScanned={(...args) => {
const data = args[0].data;
result = JSON.stringify(result);
console.log(result);
navigation.navigate('your_next_screen',{result});
);
}}
barCodeScannerSettings={{
barCodeTypes: ['qr'],
}}
style={{ flex: 1 }}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
camera: {
flex: 1,
},
buttonContainer: {
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
margin: 20,
},
button: {
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
},
text: {
fontSize: 18,
color: 'white',
},
});
export default QrcodeReader;
Welcome @Backup Gov18,
This is a documented issue.
Note: Only one active BarCodeScanner preview is supported currently. When using navigation, the best practice is to unmount any previously rendered BarCodeScanner component so the following screens can use without issues.
There is a workaround.
Instead of conditionally rendering the <BarcodeScanner />
component, you could render it inside another dedicated screen component.
This way, after this new screen reads the barcode, you could navigate back to your first screen. Navigating back may unmount this new screen. You can force unmount if you need to.
As you are using react-navigation
, you had better use .pop()
instead of goBack()
.
You can also use expo-camera
instead of expo-barcode-scanner
. expo-camera
does not have this issue. It also offers more options like flashlight/torch and switching cameras.
I faced the same problem and because it was a feature i couldnt work without, i persisted and found a solution that worked for me.
Because Only one active BarCodeScanner preview is supported, I went to react navigation and found a way to re-render the barcode scanner whenever the screen is in focus.
import { useIsFocused } from '@react-navigation/native'; useIsFocused returns true when a screen with the barcode scanner is the one in focus.
{isFocused ? (
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>) : null}
Read more on https://reactnavigation.org/docs/use-is-focused.
Full Example:
import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import { useIsFocused } from '@react-navigation/native';
export default function App() {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
console.log(hasPermission, scanned);
const isFocused = useIsFocused();
useEffect(() => {
(async () => {
setScanned(false);
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
alert(`Bar code with type ${type} and data ${data} has been scanned!`);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
{isFocused ? (
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
) : null}
{scanned && (
<Button title={'Tap to Scan Again'} onPress={() => setScanned(false)} />
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
},
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With