mgcrea / vision-camera-barcode-scanner

High performance barcode scanner for React Native using VisionCamera
MIT License
84 stars 11 forks source link

Unable to call 'setState' within 'onBarcodeScanned' #5

Closed zzz08900 closed 10 months ago

zzz08900 commented 11 months ago

Here's what I tried:

  const { props: cameraProps, highlights } = useBarcodeScanner({
    fps: 5,
    onBarcodeScanned: (newData) => {
      'worklet';
      setBarCode(newData);
    },
  });

And I got the error message: Regular javascript function 'bound dispatchSetState' cannot be shared. Try decorating the function with the 'worklet' keyword to allow the javascript function to be used as a worklet.

zzz08900 commented 11 months ago

OK I think I managed to put together a rather hacky solution

const [barCode, setBarCode] = useState('');

const setBarCodeJs = Worklets.createRunInJsFn(setBarCode);
const frameProcessor = useFrameProcessor((frame) => {
    'worklet';
    runAtTargetFps(5, () => {
      'worklet';
      // Call the native barcode scanner
      const barcodes = scanCodes(frame);
      // console.log(JSON.stringify(barcodes, null, 2));

      if (barcodes.length > 0) {
        setBarCodeJs(barcodes[0]);
      }
    });
  }, []);

return <Camera
            style={styles.cameraScanner}
            device={device}
            isActive
            frameProcessor={frameProcessor}
            pixelFormat={Platform.OS === 'ios' ? 'native' : 'yuv'}
          />

Good thing scanCodes was exported :)

If this is one of the intended usage of the library (my guts feeling tells me its not) should we add it to the docs?

mgcrea commented 11 months ago

onBarcodeScanned is called on the GPU thread so it is expected that you can't call setState without wrapping it first with Worklets.createRunInJsFn, indeed the docs are lacking in that regard.

Did you this simpler code without having to call scanCode yourself?

 const setBarCodeJs = Worklets.createRunInJsFn(setBarCode);
 const { props: cameraProps, highlights } = useBarcodeScanner({
    fps: 5,
    onBarcodeScanned: (newData) => {
      'worklet';
      setBarCodeJs(newData);
    },
  });
zzz08900 commented 11 months ago

Last time I tried it I ended up with a black camera view. I'll double check.

onBarcodeScanned is called on the GPU thread so it is expected that you can't call setState without wrapping it first with Worklets.createRunInJsFn, indeed the docs are lacking in that regard.

Did you this simpler code without having to call scanCode yourself?

 const setBarCodeJs = Worklets.createRunInJsFn(setBarCode);
 const { props: cameraProps, highlights } = useBarcodeScanner({
    fps: 5,
    onBarcodeScanned: (newData) => {
      'worklet';
      setBarCodeJs(newData);
    },
  });

That works to some extent. If you don't pass a ref the camera view then everything works fine. If somehow people need a ref in camera view for focusing/taking photo/etc then the camera freezes after one single scan.

Are we supposed to use the ref returned by useBarcodeScanner ?

zzz08900 commented 11 months ago

Personally I feel like adding a ref to camera view from inside useBarcodeScanner is kinda invasive to user's code layout. Maybe change that to be optional and only add a ref to camera view when highlighting is enabled?

mgcrea commented 11 months ago

@zzz08900 does your code works if you don't pass the ref from the hook to the <Camera /> component? iirc currently we don't use so not sure if it is actually the culprit. The idea was to enable focus on touch for scanning barcodes in the future.

zzz08900 commented 11 months ago

If I pass ref from the hook to the component, code scanning works all fine. Didn't try the highlighting. So yeah we are supposed to use the ref returned by useBarcodeScanner. Now I just need to find a elegant way of storing the ref somewhere so I can do focusing/photo taking, etc while scanning codes.

What happened on my side was I have focusing/zooming/photo taking all set up using my own ref, which seems had created some sort of conflict.

mgcrea commented 10 months ago

Closing this for now, check if you still have issues with the latest release and reopen if needed! Thanks