Camera-Based Barcode Scanning in React
Food Tracker (React + Express)
Chapter 4 · Camera-Based Barcode Scanning in React
This chapter builds the piece of the app that feeds Chapter 3's Express route a barcode in the first place — and it's the one chapter in this entire course with no Express, no Node, and no server involvement at all. Everything here runs in the browser, which is exactly why this exact component was already built once before: Food Tracker (React + Firebase)'s own Chapter 4 built it first, and what follows is that same code, unchanged.
Requesting Camera Access
facingMode: "environment" requests the rear camera on a phone — the one actually useful for scanning a product. getUserMedia also only works over HTTPS (or localhost during development) — worth knowing now, and something to check specifically once Chapter 11 deploys this app for real, since an Express deployment doesn't get HTTPS by default the automatic way Firebase Hosting does.
Decoding Barcodes From Video Frames
Two genuinely different approaches exist. The native browser BarcodeDetector API is fast and built in — but as of general browser support, it's available in Chrome/Edge on Android and desktop, and not in Safari on iOS. A JS library like ZXing (@zxing/browser) works everywhere, at some added CPU cost, since it decodes frames in pure JavaScript rather than using a native implementation. The practical pattern: try BarcodeDetector where it exists, fall back to ZXing where it doesn't.
Note what this hook does not import, call, or reference anywhere: no fetch to a specific URL, no backend SDK, nothing at all. It only calls one thing — onDetected(barcode) — a plain callback prop the parent supplies. That single design decision is exactly what makes reusing it unchanged possible.
Wiring It to This Course's Own Backend
The only place this course's own identity shows up is in the parent component's callback — everything above this point is identical, character for character, to what Food Tracker (React + Firebase)'s own Chapter 4 already built:
Compare this to Food Tracker (React + Firebase)'s own handleDetected, which called a Cloud Function (lookupBarcode({ barcode })) instead of a plain fetch. That one line is the entire difference between the two courses' use of this component — a callable Cloud Function on one side, a REST fetch call on the other, both feeding an identical scanning hook.
"BarcodeDetector" in window being false doesn't throw an error; it just quietly does nothing unless the fallback path is genuinely built and tested, not just sketched in a comment.
Where This Course Is Headed
The add-item flow next — a React form component plus an Express POST endpoint, taking this scanned barcode's lookup result the rest of the way into the database, with client- and server-side validation both covered honestly.
Hands-On Exercises
Explain exactly what changed and what stayed identical between this chapter's ScanScreen and Food Tracker (React + Firebase)'s own version of it. Why does so little actually need to change?
📄 View solutionExplain what happens if the useEffect cleanup function omits stream?.getTracks().forEach(track => track.stop()), and why this matters specifically for a scan screen a user might navigate to and away from repeatedly.
📄 View solutionExplain why leaving the ZXing fallback as an unimplemented stub could pass all of a developer's own testing and still be a real bug in production. Which users specifically would be affected, and why wouldn't Chrome-based testing ever catch it?
📄 View solutionChapter 4 Quick Reference
- This component is reused, not rebuilt — identical to Food Tracker (React + Firebase) Chapter 4's own useBarcodeScanner hook
facingMode: "environment"— the rear camera, not the front-facing oneBarcodeDetector— native, fast, Chrome/Edge/Android; not on Safari/iOS — needs a ZXing fallback- Cleanup — always stop every track from the stream in the effect's cleanup function, or the camera stays on after unmount
- The one line that differs: handleDetected calls fetch("/api/lookup/...") here, vs. a Cloud Function in the Firebase course
- Next chapter: Building the Add-Item Flow