0

Actually i'm new to React and i'm trying to make a simple barcode scanner which show the scanned barcode in an alert and after pressing "OK" in the alert the user should be able to scan another barcode.

The issue is that the barcode is continuously scanned and when the alert is up it's hiding and showing every second the alert.

I was trying to do something like this to show the alert only once and if OK is pressed to be able to show again the alert but only in case the OK is pressed but that had no effect..

  onBarCodeRead = (e) => {
    if(!this.alertPresent){
      this.alertPresent = true;
          Alert.alert(
            "Barcode type is " + e.type,
            "Barcode value is " + e.data,
            [
                 {text: 'OK', onPress: () => this.alertPresent = false;},
            ],
              {cancelable: false},
          );
      }
  }

Here is full code of Barcode.JS

import React, { Component } from 'react';
import { Button, Text, View,Alert } from 'react-native';
import { RNCamera } from 'react-native-camera';
import BarcodeMask from 'react-native-barcode-mask';
class ProductScanRNCamera extends Component {

  constructor(props) {
    super(props);
    this.camera = null;
    this.barcodeCodes = [];
    this.alertPresent = false;
    this.state = {
      camera: {
        flashMode: RNCamera.Constants.FlashMode.auto,
      }
    };
  }

  onBarCodeRead = (e) => {
    if(!this.alertPresent){
      this.alertPresent = true;
          Alert.alert(
            "Barcode type is " + e.type,
            "Barcode value is " + e.data,
            [
                 {text: 'OK', onPress: () => this.alertPresent = false;},
            ],
              {cancelable: false},
          );
      }
  }


  pendingView() {
    return (
      <View
      style={{
        flex: 1,
        backgroundColor: 'lightgreen',
        justifyContent: 'center',
        alignItems: 'center',
      }}
      >
      <Text>Waiting</Text>
      </View>
    );
  }

  render() {


    return (
      <View style={styles.container}>
      <RNCamera
      ref={ref => {
        this.camera = ref;
      }}
      defaultTouchToFocus
      flashMode={this.state.camera.flashMode}
      mirrorImage={false}
      onBarCodeRead={this.onBarCodeRead.bind(this)}
      onFocusChanged={() => {}}
      onZoomChanged={() => {}}
      style={styles.preview}
      >
      <BarcodeMask/>
      </RNCamera>
      </View>
    );
  }
}
NiceToMytyuk
  • 3,644
  • 3
  • 39
  • 100

2 Answers2

7

The trick here is to modify barcodeTypes props with an internal state.

const defaultBarcodeTypes = [// should be all Types from RNCamera.Constants.BarCodeType];

class ProductScanRNCamera extends Component {
   state = {
      // your other states
      barcodeType: '',
      barcodeValue: '',
      isBarcodeRead: false // default to false
   }

   onBarcodeRead(event) {
      this.setState({isBarcodeRead: true, barcodeType: event.type, barcodeValue: event.data});
   }

   // run CDU life-cycle hook and check isBarcodeRead state
   // Alert is a side-effect and should be handled as such.
   componentDidUpdate() {
      const {isBarcodeRead, barcodeType, barcodeValue} = this.state;
      if (isBarcodeRead) {
         Alert.alert(barcodeType, barcodeValue, [
           { 
               text: 'OK', 
               onPress: () => {
                   // Reset everything 
                   this.setState({isBarcodeRead: false, barcodeType: '', barcodeValue: ''})
               }
           }
         ]);
      }

   }

   render() {
      const {isBarcodeRead} = this.state;
      return (
         <RNCamera {...your other props} barcodeTypes={isBarcodeRead ? [] : defaultBarcodeTypes}>
            <BarcodeMask />
         </RNCamera>
      )

   }
}

A hook version is cleaner

const ProductScanRNCamera = () => {
   const [isBarcodeRead, setIsBarcodeRead] = useState(false);
   const [barcodeType, setBarcodeType] = useState('');
   const [barcodeValue, setBarcodeValue] = useState('');

   useEffect(() => {
      if (isBarcodeRead) {
          Alert.alert(
             barcodeType, 
             barcodeValue, 
             [
                {
                    text: 'OK',
                    onPress: () => {
                        // reset everything
                        setIsBarcodeRead(false);
                        setBarcodeType('');
                        setBarcodeValue('');
                    }
                }
             ]
          );
      }

   }, [isBarcodeRead, barcodeType, barcodeValue]);

   const onBarcodeRead = event => {
      if (!isBarcodeRead) {
         setIsBarcodeRead(true);
         setBarcodeType(event.type);
         setBarcodeValue(event.data);
      }
   }

   return (
      <RNCamera {...your props} 
                onBarCodeRead={onBarcodeRead} 
                barcodeTypes={isBarcodeRead ? [] : defaultBarcodeTypes}>
         <BarcodeMask />
      </RNCamera>
   )
}
Chau Tran
  • 4,668
  • 1
  • 21
  • 39
  • I need to navigate to different screen on barcode read with the data. Is there any way to prevent re-render? I also want to ensure that once user come back to scanner, it should allow user. – Hardik Shah Nov 23 '22 at 16:22
0

use setState in order to set state of component.setState will take the object and update the state of component

check code below

import React, { Component } from 'react';
import { Button, Text, View, Alert } from 'react-native';
import { RNCamera } from 'react-native-camera';
import BarcodeMask from 'react-native-barcode-mask';
class ProductScanRNCamera extends Component {

  constructor(props) {
    super(props);
    this.camera = null;
    this.barcodeCodes = [];
    this.showAlert = true;
    this.state = {
      camera: {
        flashMode: RNCamera.Constants.FlashMode.auto,
      }
    };
  }

  onBarCodeRead = (e) => {
    if (this.state.alertPresent) {
      this.setState({ showAlert: false });
      Alert.alert(
        "Barcode type is " + e.type,
        "Barcode value is " + e.data,
        [
          { text: 'OK', onPress: () =>console.log('ok')  },
        ],
        { cancelable: false },
      );
    }
  }


  pendingView() {
    return (
      <View
        style={{
          flex: 1,
          backgroundColor: 'lightgreen',
          justifyContent: 'center',
          alignItems: 'center',
        }}
      >
        <Text>Waiting</Text>
      </View>
    );
  }

  render() {

    return (
      <View style={styles.container}>
        <RNCamera
          ref={ref => {
            this.camera = ref;
          }}
          defaultTouchToFocus
          flashMode={this.state.camera.flashMode}
          mirrorImage={false}
          onBarCodeRead={this.onBarCodeRead.bind(this)}
          onFocusChanged={() => { }}
          onZoomChanged={() => { }}
          style={styles.preview}
        >
          <BarcodeMask />
        </RNCamera>
      </View>
    );
  }
}
Aurangzaib Rana
  • 4,028
  • 1
  • 14
  • 23