Seamless Interaction: Boosting React Apps with Barcode and QR Code Scanners
- Jun 14, 2024
- 6 min read
Updated: Jun 21, 2024
By Nikos Rzewucki, Frontend Developer
Sometimes, when creating a frontend application for professionals, we encounter a UX problem where users must repeatedly input certain information to interact with the app. This issue can be prevalent in various use cases, such as retail, logistics, staff management, and more. Visual integrations, particularly QR codes and barcodes, can be a huge help in these scenarios. Physical scanning devices are usually an inexpensive solution that saves users a lot of time and allows for seamless integration. This article presents how to integrate these technologies into a React application.
What are barcodes and QR codes?
A barcode is a visual representation of data in the form of parallel lines of varying widths and spacings. It is one-dimensional (1D) and is used to store and read information such as product numbers, inventory codes, and other identifiers. Due to its popularity and standardization, they are easily understandable and acknowledged by most people. The most widespread standard is “Code 128” which can encode 128 ASCII characters in the most compressed form.
A QR code (Quick Response code) is a type of two-dimensional barcode that can store a significant amount of information compared to traditional barcodes. It is characterized by its square shape and black-and-white patterns, which can be scanned using a camera-equipped device like a smartphone or a QR code reader. QR codes have much higher capacity and possibilities than barcodes and can hold data such as URLs, text, contact information, and more.
For consistency, this article will focus on QR codes, however the solution can be applied to any code type.
Scanning
There are a variety of options to scan prepared QR code. Both a dedicated reader device and a built-in camera can be used, however the first one provides quicker and seamless operation. Scanner, as a physical device is a simple input device, a “keyboard that types very fast”. It can operate both in wire and wireless way.
How to make it work?
Several issues need to be addressed to ensure functionality. The most significant issue is related to the input stream: determining when to start and stop reading. As QR codes can contain various types of content, it is essential to establish the start and end points of the input stream. Several methods are available to achieve this and choosing one should be preceded by a consideration of the use case and, most importantly, the format of the code.
Options to determine the start of a reading:
Matching Prefix Pattern – If it is known that the code will have a specific pattern, or if a specific pattern can be enforced, this method is advisable. Examples include a URL (`HTTPS://<...>`), a number with a known prefix (`0000.<...>`), or a custom pattern (`myCode:<...>`). This allows the input stream to be identified as starting from the QR code without any additional actions required in advance.
User Interaction – User can be asked to specify when they wish to scan a QR code, such as by clicking a button in the app that opens the input stream. Everything entered following this interaction is then considered part of the QR code.
Read Everything – In applications that do not involve text input or other keyboard interactions, every text input can be treated as a QR code read.
Options to determine the end of a reading:
Matching Suffix Pattern – If the QR code consistently ends with a specific character, or if a special character can be designated to mark the end (e.g., `Name Surname^`), this method can be used. After reading this character or sequence of characters, the input stream will be closed.
Matching Input Length – For QR codes of a fixed length, such as phone numbers, parcel numbers, or employee IDs, only a predefined number of characters may be read. This can also be combined with a matching prefix, where a given QR code type in the application always has a fixed length.
Reading Timeout – Since most scanners read QR codes character by character with a few milliseconds delay between each, a fixed timeout can be defined for closing the input stream. For example, if no new character is provided within 200 milliseconds, the input stream will be closed.
Scanner Newline – Many scanners are configured to end a QR code read with a newline character (`/n`, `Enter`). This character is not printed in the code itself but is added by the scanner during the reading process. This is a useful option to consider if the input is a single-line string.
Another aspect to consider, depending on the use case, is which HTML element should be focused. In some cases, the best user experience would involve a separate component for handling scanning upon clicking. In such cases, it must be ensured that typing events do not bubble up and disable propagation. If occasional scanning is desired while the application is in operation, the window element is likely the best choice.
Example
Consider an application designed for parcel tracking using QR codes. These QR codes have the format of a URL with a unique identifier of variable length, and it should be possible to scan them seamlessly at any time while using the application.
For a React application, a custom hook is well-suited for this purpose:
export const useDebouncedQRListener = () => { }; The first task is to handle typing events. This can be accomplished by using the `keydown` event, so the following can be added to the custom hook:
useEffect(() => {
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [handleKeyDown]); Next, two states are needed: the first to maintain the current buffer, which acts as a stack for storing read characters, and the second to store and return the combined input value, which will be returned by the hook. The buffer can be a simple string; however, in the discussed use case, the input value should be comparable by reference. To ensure that the hook returns a value even when the same QR code is scanned twice in succession, the input should be set as an object. This way, it will be compared by reference and will be considered changed by React every time a new value is created. The other option would be to reset the value and return empty string after setting an input with value.
const [buffer, setBuffer] = useState("");
const [input, setInput] = useState({ qrCode: "" });
...
return input; Next, a handler for `keydown` is needed, which was previously used in `useEffect`.
const handleKeyDown = useCallback(
(event: KeyboardEvent) => {
setBuffer((prev) => prev + event.key);
}, []); After setting up the buffer, the input needs to be set according to the specific use case outlined earlier. For the discussed example, a buffer reading timeout will be used: if there is a 200 ms delay between keystrokes, it will be considered that the QR input has ended. This can be achieved using a debouncing technique. Debouncing can be implemented manually or by using an external library, such as `use-debounce`. The `useDebounceCallback` function delays the execution of a given function for a specified time and cancels it when the new call happens within that time. As a result, the input will only be set when the QR reader stops receiving new characters.
const debouncedSetInput = useDebouncedCallback((buffer) => {
setInput({ qrCode: buffer });
}, 200); Next, `debouncedSetInput` should be called every time the buffer changes. There is no need to set an input after the buffer is cleared, unless the hook is intended to return an empty string between scans.
useEffect(() => {
if (buffer.length) {
debouncedSetInput(buffer);
}
}, [buffer, debouncedSetInput]); Finally, the buffer clear is needed, after the input has been changed:
useEffect(() => {
setBuffer("");
}, [input]);
Let’s use the following code in app parent component to test the behavior.
const scannerOutput = useDebouncedQRListener();
useEffect(() => {
const { qrCode } = scannerOutput;
qrCode && window.alert(`You have scanned QR code: ${qrCode}`);
}, [scannerOutput]); Depending on the QR code and scanner settings, there may be situations where the 'Shift' key is added at the beginning of the input stream. To address this issue, certain special keys can be excluded.
const EXCLUDED_KEYS = ["Shift", "Control", "Alt", "Meta", "Clear", "CapsLock"];
const handleKeyDown = useCallback(
(event: KeyboardEvent) => {
if (EXCLUDED_KEYS.includes(event.key)) {
return;
}
setBuffer((prev) => prev + event.key);
}, [debouncedSetInput]);
To enhance the stability of the solution, especially when scanning or typing quickly, additional validation can be added. In this example, only URL-based QR codes are expected to be scanned. Therefore, any input that is not a URL can be ignored by extending the `debouncedSetInput` method.
enum QRType {
URL = "HTTPS://",
}
...
const debouncedSetInput = useDebouncedCallback((buffer) => {
if (buffer.toUpperCase().startsWith(QRType.URL)) {
setInput({ qrCode: buffer });
} else {
setBuffer('');
}
}, 200);Moreover, the scanner can be configured to add a newline at the end of each scanned QR code. When a newline is received, there is no need to wait for the debounce period; the setter can be executed immediately. The `useDebouncedCallback` function has a `flush()` method for such cases. This condition can be added to the `handleKeyDown` function.
const FLUSH_KEYS = ["Enter"];
if (FLUSH_KEYS.includes(event.key)) {
debouncedSetInput.flush();
return;
} The complete code looks like this:
import { useCallback, useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce";
const EXCLUDED_KEYS = ["Shift", "Control", "Alt", "Meta", "Clear", "CapsLock"];
const FLUSH_KEYS = ["Enter"];
enum QRType {
URL = "HTTPS://"
};
export const useDebouncedQRListener = () => {
const [buffer, setBuffer] = useState("");
const [input, setInput] = useState({ qrCode: "" });
const debouncedSetInput = useDebouncedCallback((buffer) => {
if (buffer.toUpperCase().startsWith(QRType.URL)) {
setInput({ qrCode: buffer });
} else {
setBuffer('');
}
}, 200);
const handleKeyDown = useCallback(
(event: KeyboardEvent) => {
if (EXCLUDED_KEYS.includes(event.key)) {
return;
}
if (FLUSH_KEYS.includes(event.key)) {
debouncedSetInput.flush();
return;
}
setBuffer((prev) => prev + event.key);
}, [debouncedSetInput]);
useEffect(() => {
if (buffer.length) {
debouncedSetInput(buffer);
}
}, [buffer, debouncedSetInput]);
useEffect(() => {
setBuffer("");
}, [input]);
useEffect(() => {
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [handleKeyDown]);
return input;
};The final effect will look like this:
As demonstrated, integrating QR code scanning into applications can be achieved quickly and easily, significantly enhancing user experience. By utilizing a custom hook in React, managing typing events, and implementing debouncing, QR codes can be captured and processed effortlessly. This not only simpliclickingfies application interaction but also adds valuable functionality for seamless user engagement.





Cила и смелость вдохновляют. Игры дают нам возможность примерить на себя образ героя, которого в реальной жизни мы могли бы побаиваться. Преодолевая врагов и трудности, игровые автоматы дают дозу уверенности и ощущение личного роста, даже если это всего лишь виртуальный мир. Кроме того, такие персонажи делают игровой процесс более динамичным и увлекательным. Когда герой способен на смелые поступки и неожиданные решения, каждое действие игрока становится значимым, а игровой мир — живым и захватывающим.
Great post about the Big Mumbai game. It’s really helpful to find clear and easy-to-understand information like this, especially for users who are new and want to explore the platform. Your explanation makes everything simple and gives a good idea of how it works. Many people look for guides like this before getting started. Thanks for sharing such informative and user-friendly content, it will definitely help readers understand the platform better.
This article offers a practical look at how integrating barcode and QR code scanning can improve efficiency in React applications, especially in scenarios where users frequently enter the same information. Using scanners as input devices can streamline workflows and reduce manual data entry, which is valuable for areas like logistics or staff management.
It’s also interesting to see how solutions like this are being implemented within modern frontend stacks, since frameworks such as React are often included among the most popular web development frameworks used to build interactive and scalable web applications today.
Salut ! C'est un sujet super intéressant, surtout que l'intégration des scans de QR codes dans une app React, c'est parfois une vraie galère avec les permissions de la caméra selon les navigateurs mobiles... j'ai pas mal galéré là-dessus le mois dernier.
D'ailleurs, ça me fait penser qu'en bossant sur un projet de mini-jeux web un peu similaire à ce que fait l'équipe de Lucky treasure casino ( ), j'ai remarqué que la rapidité de réponse du scanner changeait tout pour la rétention des utilisateurs. Au début, mon truc ramait un peu sur les vieux Android et j'avais peur que personne n'ait la patience d'attendre.
Est-ce que vous avez testé la librairie mentionnée avec des caméras un peu bas de…
This was an interesting read, especially the focus on making interactions faster and more intuitive with barcode and QR code scanners in React apps. I keep thinking how similar ideas can be applied beyond food tech and logistics, including people management. In HR processes like onboarding, attendance tracking, or access control, seamless scanning and real-time data sync can remove a lot of friction. That’s one of the reasons why modern HR Software benefits so much from smart integrations and automation. When employee records, approvals, and workflows are centralised, teams save time and reduce errors. Clean tech foundations like the ones described here really set the stage for better HR experiences.