IlmHamroh
JavaScript Full-stack/21-qism. React: media, integratsiyalar, PWA16/32-dars20 daqiqa
Mundarija (27)

QR kod React'da: qrcode.react, logo, kamera bilan skanerlash va shtrix-kod

Qisqacha: QR kod — matnni (ko'pincha havolani) qora-oq kvadratchalarga aylantirish. React'da eng qulay yo'l — qrcode.react: <QRCodeSVG value={havola} level="M" /> oddiy SVG chizadi (+6.0 KB gzip, Trusted Types bilan muammosiz). Matn qancha uzun va xatoni tuzatish darajasi (L, M, Q, H) qancha yuqori bo'lsa, kod shuncha zich. Markazga logo qo'yilsa — H daraja. Skanerlash uchun kamera kerak (getUserMedia, faqat HTTPS va ruxsat bilan). Kodni BarcodeDetector (hamma joyda yo'q) yoki kutubxona taniydi. Kutubxonalardan html5-qrcode (+104.7 KB) Trusted Types ostida ochilmadi, @yudiel/react-qr-scanner (+56.7 KB) WASM'ni CDN'dan yuklaydi. vazifalar da: vazifa havolasi QR kodi — faqat «Ulashish» ochilganda yuklanadigan 6.1 KB chunk.

Bu darsda

  • qrcode.react bilan QR kod chizasiz va versiya, xatoni tuzatish darajasi, chet maydonini tushuntirasiz.
  • Markazga logo qo'yasiz va nega buning uchun H daraja kerakligini bilasiz.
  • QR komponentini kech yuklaysiz — faqat foydalanuvchi ochganda.
  • Kamera bilan skanerlash oqimini (getUserMedia, BarcodeDetector, tozalash) yozasiz va kutubxonalarni solishtirasiz.
  • Shtrix-kod (EAN-13) nazorat raqamini hisoblaysiz va QR orqali firibgarlikdan himoyalanasiz.

Oldin bilishingiz kerak: Rasm UI React'da, Web Audio, kamera va mikrofon (getUserMedia), Clipboard va Web Share API, lazy va code splitting, Suspense.

1. Nega bu kerak?

Oldingi darsda ro'yxatni Excel'ga chiqardik. Endi — ma'lumotni telefonga uzatish. «Bahor» stollarida kichik kartochka turadi: telefon kamerasini to'g'rilasangiz, menyu ochiladi. Kassada esa to'lov QR kodi. Omborda Sardor mahsulot qutisidagi shtrix-kodni skanerlaydi.

QR kod — kompyuterdan telefonga eng tez "ko'prik": havolani qo'lda terish shart emas. vazifalar da ham xuddi shu: kompyuterda ochiq vazifani telefonda davom ettirish uchun QR kod.

Hayotiy o'xshatish: pochta indeksi. Xat tashuvchi manzilni o'qimaydi — indeksni mashina o'qiydi. QR kod ham manzilni odam uchun emas, kamera uchun yozadi.

2. QR kod qanday tuzilgan

2.1 Birinchi QR kod

Natija oynasida qrcode.react 4.2.0 ishlaydi (kanondagi versiya):

jsx
import { useEffect, useRef } from "react";
import { QRCodeSVG } from "qrcode.react";

export default function App() {
  const ref = useRef(null);
  useEffect(() => {
    const svg = ref.current;
    const attr = (name) => svg.getAttribute(name);
    console.log(attr("viewBox"), attr("role"));
    console.log(svg.querySelectorAll("path").length, "ta path");
  }, []);
  return (
    <QRCodeSVG
      ref={ref}
      value="https://example.com/vazifa/2"
      size={160}
      level="M"
      marginSize={2}
      title="Vazifa havolasining QR kodi"
    />
  );
}

Konsolda:

text
0 0 33 33 img
2 ta path

«Ishga tushir» — 160 piksellik QR kod. Telefoningiz kamerasini ekranga to'g'rilang: https://example.com/vazifa/2 taklif qilinadi. Konsoldagi qatorlar ichki tuzilishni ko'rsatadi:

  • viewBox="0 0 33 33" — kod 33×33 katakdan iborat. Ulardan 29×29 — kodning o'zi, har tomondan 2 katak — chet maydoni (marginSize={2}).
  • 2 ta path — bittasi oq fon, ikkinchisi — hamma qora kataklar bitta yo'lda. Shuning uchun SVG yengil: 841 katak uchun ikkita element.
  • role="img" va title — Malikaning ekran o'quvchisi uni "Vazifa havolasining QR kodi, rasm" deb o'qiydi.

2.2 Versiya va xatoni tuzatish darajasi

QR kodning o'lchami versiya bilan o'lchanadi: 1-versiya — 21×21 katak, har keyingisi +4, 40-versiya — 177×177. Kutubxona versiyani matn uzunligi va xatoni tuzatish darajasiga qarab o'zi tanlaydi. Daraja — kodning qancha qismi buzilsa (dog', yirtiq, logo) ham o'qilishi:

Daraja Tiklanadigan qism (taxminan)
L 7%
M 15%
Q 25%
H 30%

Ikki havola va uch daraja bilan sinaymiz:

jsx
import { useEffect, useRef } from "react";
import { QRCodeSVG } from "qrcode.react";

const SHORT = "https://example.com/v/2";
const LONG =
  "https://example.com/vazifalar/ru/vazifa/2" +
  "?utm_source=qr&utm_medium=stol&utm_campaign=bahor_kuz";
const CASES = [
  ["qisqa", SHORT, "L"],
  ["qisqa", SHORT, "M"],
  ["qisqa", SHORT, "H"],
  ["uzun", LONG, "M"],
  ["uzun", LONG, "H"],
];

export default function App() {
  const box = useRef(null);
  useEffect(() => {
    const svgs = box.current.querySelectorAll("svg");
    CASES.forEach(([name, value, level], i) => {
      const n = svgs[i].getAttribute("viewBox").split(" ")[2];
      const version = (n - 17) / 4;
      const label = `${name} (${value.length} belgi), ${level}`;
      console.log(`${label}: ${n}×${n}, versiya ${version}`);
    });
  }, []);
  return (
    <div ref={box}>
      {CASES.map(([name, value, level]) => (
        <QRCodeSVG
          key={name + level}
          value={value}
          level={level}
          size={64}
        />
      ))}
    </div>
  );
}

Konsolda:

text
qisqa (23 belgi), L: 25×25, versiya 2
qisqa (23 belgi), M: 25×25, versiya 2
qisqa (23 belgi), H: 29×29, versiya 3
uzun (94 belgi), M: 41×41, versiya 6
uzun (94 belgi), H: 53×53, versiya 9

Bu yerda marginSize berilmagan — sukut bo'yicha 0, shuning uchun viewBox = kodning o'zi va (n - 17) / 4 versiyani beradi. Xulosalar:

  • Qisqa havola — oddiy kod. 94 belgili havola H da 53×53: katakchalar mayda, stol ustidagi kartochkada eski telefon uni qiyin o'qiydi. UTM parametrlari kerak bo'lsa, ularni qisqa havola orqasiga yashiring.
  • M — oqilona sukut. Ekranda (dog' tushmaydi) L yoki M yetadi. Qog'ozda, ayniqsa oshxonada — Q.
  • Chet maydoni (quiet zone) — kod atrofidagi oq hoshiya. QR standarti 4 katak tavsiya qiladi, kanon 2 qo'ydi va QR'ni oq fonga joyladi (atrofidagi oq ham hoshiya vazifasini bajaradi). Telefon skanerlarini biz sinamadik — o'z loyihangizda albatta sinang. Hoshiyasiz kod qorong'i fonda o'qilmasligi mumkin.

Rang. Skaner qora-oq kontrastga tayanadi. Qorong'i temada QR'ni "teskari" (oq kataklar qora fonda) qilmang — ko'p skanerlar o'qimaydi. Kanon CSS'i shu sababli QR'ga doim oq fon beradi: #qr-kod { background: #fff; }.

Tekshirib ko'ring: Nega qisqa havolada L va M bir xil o'lchamli (25×25), H esa kattaroq?

Javob

Har versiyaga ma'lum miqdorda ma'lumot sig'adi, qolgan joy xatoni tuzatish kodiga ketadi. 23 belgi 2-versiyaga L bilan ham, M bilan ham sig'di — joy yetarli. H esa joyning ko'p qismini tuzatish kodiga beradi va 23 belgi 2-versiyaga sig'may qoldi — kutubxona 3-versiyani tanladi. Daraja oshgani sari bir xil matn uchun kod kattalashadi.

Ko'p kompaniyalar QR markaziga logo qo'yadi. Logo kodning bir qismini berkitadi — ya'ni "dog'". Shuning uchun daraja H bo'lishi va logo kichik bo'lishi shart:

jsx
import { useEffect, useRef } from "react";
import { QRCodeSVG } from "qrcode.react";

const LOGO =
  "data:image/svg+xml," +
  encodeURIComponent(
    '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">' +
      '<circle cx="5" cy="5" r="5" fill="#1f6f4a"/></svg>',
  );

export default function App() {
  const ref = useRef(null);
  useEffect(() => {
    const image = ref.current.querySelector("image");
    console.log(image.getAttribute("width"), image.getAttribute("x"));
  }, []);
  return (
    <QRCodeSVG
      ref={ref}
      value="https://example.com/v/2"
      level="H"
      size={160}
      imageSettings={{
        src: LOGO,
        width: 32,
        height: 32,
        excavate: true,
      }}
    />
  );
}

Konsolda:

text
5.8 11.6

imageSettings da width: 32 — piksel (160 lik kod ichida). SVG ichida u katak birligiga o'girilgan: 29 katakli kodda 32/160 × 29 = 5.8 katak, markazda (x = 11.6). Logo kodning ≈ 4% ini egallaydi — H ning 30% zaxirasi bemalol yetadi. excavate: true — logo ostidagi kataklar o'chiriladi: logo shaffof bo'lsa ham qora-oq dog' aralashmaydi.

Qoida: logo kodning eni bo'yicha beshdan biridan oshmasin va har doim haqiqiy telefonlarda sinab ko'ring — eski telefon va yomon yorug'likda ham.

3. React'da QR: qachon yuklash

QR kod har sahifada kerak emas — faqat foydalanuvchi «Ulashish» ni bosganda. qrcode.react kichik (+6.0 KB), lekin birinchi yuklashdagi har kilobayt sezilarli (Yuklanishni optimallashtirish darsida chuqurroq). Kanon QR komponentini lazy bilan ajratdi va uni details tegi ochilgandagina chizadi.

Natija oynasida dinamik import() yo'q, shuning uchun kechikishni Promise bilan taqlid qilamiz (300 ms). Kanon aynan shunday tuzilgan:

jsx
import { lazy, Suspense, useState } from "react";
import { QRCodeSVG } from "qrcode.react";

// Loyihada: lazy(() => import("./QrKod.tsx")) — alohida chunk
const QrCode = lazy(
  () =>
    new Promise((resolve) =>
      setTimeout(
        () =>
          resolve({
            default: ({ link }) => (
              <QRCodeSVG value={link} size={128} title="QR kod" />
            ),
          }),
        300,
      ),
    ),
);

export default function App() {
  const [open, setOpen] = useState(false);
  const link = "https://example.com/vazifa/2";
  return (
    <details onToggle={(event) => setOpen(event.currentTarget.open)}>
      <summary>Ulashish (QR kod)</summary>
      {open && (
        <Suspense fallback={<p role="status">QR tayyorlanmoqda…</p>}>
          <QrCode link={link} />
        </Suspense>
      )}
      <p>
        <a href={link}>{link}</a>
      </p>
    </details>
  );
}

Ekranda:

text
Ulashish (QR kod)
QR kod
https://example.com/vazifa/2

Uch qadam jadvalda:

Qadam Holat Ekranda
sahifa ochildi open — false, chunk so'ralmagan «Ulashish (QR kod)»
details bosildi open — true, chunk kutilmoqda «QR tayyorlanmoqda…» (ekran() tekshirdi)
300 ms dan keyin chunk keldi QR rasmi va havola

open && … — muhim. Details tegi yopiq bo'lsa ham ichidagi React komponentlari chiziladi (faqat ko'rinmaydi). open state'isiz lazy chunk sahifa ochilishi bilan yuklanardi — kech yuklashdan foyda qolmasdi. onToggle — details ochilib-yopilganda keladigan hodisa.

4. Skanerlash: kamera va BarcodeDetector

4.1 Uch shart

QR'ni o'qish uchun brauzerga kamera kerak (Web Audio, kamera va mikrofon):

  1. Xavfsiz kontekst — HTTPS yoki localhost. Oddiy http:// da navigator.mediaDevices umuman yo'q.
  2. Ruxsat — brauzer foydalanuvchidan so'raydi. Rad etilsa — NotAllowedError. Saytning Permissions-Policy sarlavhasi kamerani yopib qo'ygan bo'lsa — so'ramaydi ham. Saytimizdagi natija oynasida aynan shunday: kamera yopiq, shuning uchun skaner misollari faqat kod sifatida.
  3. Kodni tanish — videodagi kadrdan QR'ni topish. Buni BarcodeDetector yoki kutubxona qiladi.

4.2 BarcodeDetector: bor joyda bepul

BarcodeDetector — brauzerning o'zi shtrix-kod va QR'ni taniydigan API: kutubxonasiz, 0 KB. Muammo — hamma joyda yo'q. Avval imkoniyatni tekshiramiz:

jsx
import { useEffect, useState } from "react";

export default function App() {
  const [info, setInfo] = useState("tekshirilmoqda…");
  useEffect(() => {
    if (!("BarcodeDetector" in window)) {
      setInfo("BarcodeDetector yo'q — kutubxona kerak");
      return;
    }
    BarcodeDetector.getSupportedFormats().then((formats) =>
      setInfo(`bor: ${formats.join(", ")}`),
    );
  }, []);
  return <p>{info}</p>;
}

Chrome 155 (Windows, headless) da ekran:

text
BarcodeDetector yo'q — kutubxona kerak

MDN ma'lumotiga ko'ra, API Android va macOS'dagi Chromium brauzerlarida bor, Windows'dagi Chrome'da esa yo'q. Telefoningizda «Ishga tushir» ni bosib ko'ring — natija boshqacha bo'lishi mumkin. Demak, BarcodeDetector — progressiv qo'shimcha (progressive enhancement): bor bo'lsa — ishlatamiz, bo'lmasa — kutubxona yoki havolani qo'lda kiritish.

4.3 Skaner komponenti

Skaner — kamera oqimi + kadr sikli + tozalash. Kod hujjat bo'yicha (natija oynasida kamera yopiq):

jsx
function QrScanner({ onResult }) {
  const video = useRef(null);
  const [error, setError] = useState("");

  useEffect(() => {
    if (!("BarcodeDetector" in window)) {
      setError("Skaner yo'q — havolani qo'lda kiriting.");
      return;
    }
    const detector = new BarcodeDetector({ formats: ["qr_code"] });
    let stream = null;
    let frame = 0;
    let stopped = false;

    navigator.mediaDevices
      .getUserMedia({ video: { facingMode: "environment" } })
      .then(async (s) => {
        if (stopped) {
          s.getTracks().forEach((t) => t.stop()); // kech keldi
          return;
        }
        stream = s;
        video.current.srcObject = s;
        await video.current.play();
        const tick = async () => {
          if (stopped) return;
          const [code] = await detector.detect(video.current);
          if (code) onResult(code.rawValue);
          else frame = requestAnimationFrame(tick);
        };
        tick();
      })
      .catch((e) =>
        setError(
          e.name === "NotAllowedError"
            ? "Kameraga ruxsat berilmadi."
            : "Kamera ochilmadi.",
        ),
      );

    return () => {
      stopped = true;
      cancelAnimationFrame(frame);
      stream?.getTracks().forEach((t) => t.stop()); // chiroq o'chadi
    };
  }, [onResult]);

  return (
    <>
      <video ref={video} muted playsInline aria-label="Kamera" />
      {error && <p role="alert">{error}</p>}
    </>
  );
}

Eng muhim qatorlar — tozalashda:

  • track.stop() — usiz kamera yoniq qoladi: telefonda yashil chiroq yonib turadi, batareya tugaydi, foydalanuvchi qo'rqadi. Komponent yopilganda kamera albatta o'chsin.
  • stopped bayrog'i — dev rejimidagi StrictMode effektni ikki marta ishga tushiradi. Birinchi getUserMedia javobi tozalashdan keyin kelishi mumkin — u holda oqimni darhol to'xtatamiz. Bu "poyga" (race condition) — kamera bilan ishlashdagi eng ko'p uchraydigan xato.
  • facingMode: "environment" — telefonning orqa kamerasi.
  • Topilgach to'xtash — natija bitta kerak, sikl davom etmaydi.

4.4 Kutubxonalar va biz sinab ko'rgan narsa

BarcodeDetector yo'q joyda kutubxona kadrni o'zi tahlil qiladi. Kanon ikkitasini vazifalar CSP'si va Trusted Types ostida o'lchadi:

text
qr-skaner-html5        JS  174889 (+ 104.7 KB) CSS      0 | CSP require-trusted-types-for×1 | xato: This document requires 'TrustedHTML' assignment. The action has been blocked. ; Failed to set the 'innerHTML' property on 'Element': This document requires 'TrustedHTML' assignment | ochiq: tashqi yo'q
qr-skaner-yudiel       JS  125735 (+  56.7 KB) CSS      0 | CSP connect-src×2,script-src×1,media-src×1 | xato: Connecting to 'https://fastly.jsdelivr.net/npm/zxing-wasm@3.1.3/dist/reader/zxing_reader.wasm' viola ; Fetch API cannot load https://fastly.jsdelivr.net/npm/zxing-wasm@3.1.3/dist/reader/zxing_reader.wasm | ochiq: tashqi fastly.jsdelivr.net
  • html5-qrcode (2.3.8, +104.7 KB) — o'z interfeysini innerHTML bilan chizadi → Trusted Types to'sdi. CSP'siz ochilganda esa headless Chrome'da kamera yo'q edi va kutubxona aniq xato berdi: Error getting userMedia, error = NotAllowedError: Permission. Paket 2023-yildan yangilanmagan.
  • @yudiel/react-qr-scanner (2.6.0, +56.7 KB) — BarcodeDetector bor bo'lsa uni ishlatadi, yo'q bo'lsa zxing kutubxonasining WebAssembly versiyasini oladi. WASM fayl esa sukut bo'yicha jsDelivr CDN'dan yuklanadi — CSP connect-src va script-src da to'sdi. CSP'siz — tashqi host fastly.jsdelivr.net. Ya'ni foydalanuvchi skanerni ochganda brauzeri uchinchi tomon serveriga murojaat qiladi. WASM faylni o'z serveringizdan berish mumkin — hujjatdagi sozlama bilan; biz buni o'lchamadik.
QR kutubxonalari: JS (gzip, React'dan tashqari)
  • uqr 0.1.3 (yaratish)CSP 03,9 KB
  • qrcode.react 4.2.0 (yaratish)CSP 0, kanonda6 KB
  • qrcode 1.5.4 (yaratish)CSP 08,7 KB
  • @yudiel/react-qr-scanner 2.6.0WASM — jsDelivr'dan56,7 KB
  • html5-qrcode 2.3.8TT to'sdi104,7 KB

Manba: O'lchandi: kanon tajribasi, Vite 8.3.3, gzip -9, Chrome 155, natijalar/tajriba/kutubxonalar-21.txt, 2026-10-17

Yaratish arzon (4–9 KB), o'qish — qimmat (57–105 KB). Uchta yaratuvchidan uqr eng kichik, lekin u SVG'ni satr qilib beradi — uni sahifaga qo'yish uchun Blob → <img> yoki innerHTML (Trusted Types) kerak. qrcode.react esa React elementlarini qaytaradi. Kanon shuning uchun uni tanladi.

Tekshirib ko'ring: Nega skaner komponentida useEffect bog'liqligida onResult bor va bu qanday muammo tug'dirishi mumkin?

Javob

onResult effekt ichida ishlatiladi — demak, u bog'liqlik (useEffect II). Agar ota komponent har renderda yangi funksiya bersa (onResult={(v) => …}), har renderda effekt qayta ishlaydi: kamera o'chadi va qayta yonadi — miltillash. Davosi: otada useCallback, yoki skaner ichida useEffectEvent bilan onResult ni reaktiv bo'lmagan qilish.

5. Shtrix-kod: EAN-13

Do'kondagi mahsulotlar qutisida — shtrix-kod (barcode): vertikal chiziqlar va ostida 13 raqam (EAN-13). Birinchi raqamlar — GS1 tashkilotining mamlakat prefiksi (O'zbekiston — 478), keyin ishlab chiqaruvchi va mahsulot, oxirgisi — nazorat raqami. U skanerlash xatosini ushlaydi: bitta raqam noto'g'ri o'qilsa, nazorat raqami mos kelmaydi.

Hisob oddiy: dastlabki 12 raqam, toq o'rindagilar ×1, juft o'rindagilar ×3, yig'indi. Nazorat raqami — yig'indini 10 ga yaxlitlash uchun yetishmagan son:

js
function ean13CheckDigit(first12) {
  const sum = [...first12].reduce((total, digit, i) => {
    const weight = i % 2 === 0 ? 1 : 3;
    return total + Number(digit) * weight;
  }, 0);
  return (10 - (sum % 10)) % 10;
}

console.log(ean13CheckDigit("400638133393")); // 1
console.log(ean13CheckDigit("478123456789")); // 2

4006381333931 — standartdagi mashhur misol: hisob 1 berdi, haqiqiy oxirgi raqam ham 1. Ikkinchi qator — o'ylab topilgan O'zbekiston kodi uchun nazorat raqami. Oxiridagi % 10 — yig'indi 10 ga bo'linsa, 10 - 0 = 10 emas, 0 bo'lsin.

Shtrix-kod chizish uchun JsBarcode kabi kutubxonalar bor (biz o'lchamadik), o'qish — o'sha BarcodeDetector (formats: ["ean_13"]) yoki skaner kutubxonalari. Kassada esa ko'pincha USB skaner ishlatiladi — u klaviatura kabi ishlaydi: raqamlarni "yozadi" va Enter bosadi. Ya'ni oddiy <input> + onKeyDown yetadi.

6. Hujumchi nigohi

QR kod odamga ko'rinmaydi — u nima ochishini faqat skanerlagach bilamiz. Firibgarlar shundan foydalanadi:

  • Quishing (QR phishing) — restoran stolidagi yoki avtoturargohdagi to'lov QR'i ustiga boshqa stiker yopishtiriladi. Mijoz "to'lov sahifasi" ga o'xshash soxta saytga kiradi va karta ma'lumotini kiritadi. Bu O'zbekistonda ham, butun dunyoda ham uchraydigan firibgarlik usuli.
  • Ilovangiz skanerlasa — natijani avtomatik ochmang. new URL(raw) bilan tahlil qiling, faqat kutilgan domen va yo'lni qabul qiling (masalan, location.origin va /vazifa/), qolganida — "Bu havola bizniki emas: example.org" deb ko'rsating.
  • QR'ga sir yozmang. QR — rasm: ekran suratiga, kamera kadriga tushadi. Kirish tokeni, bir martalik parol yoki shaxsiy ma'lumot QR'ga qo'yilsa, uni har kim o'qiydi. Kanon QR'ga faqat vazifa havolasini yozadi; ro'yxatning o'zi — shu brauzerda.

Bu holatlarda xavfsiz yechim — interfeysda domenni ko'rsatish: QR yonida havola matni turadi (kanonda shunday), foydalanuvchi qayerga ketayotganini ko'radi.

7. Vazifalar qadami: vazifa havolasi QR kod bilan (holat 16)

7.1 Fayllar

bash
git switch -c feat/qr
npm i -E qrcode.react@4.2.0

Yangi papka src/xususiyatlar/ulashish/: QrKod.tsx, VazifaUlashish.tsx, index.ts. VazifaUmumiy.tsx ga bitta qator, asos.css ga QR stillari.

QrKod.tsx — butun fayl (kanon):

tsx
// QrKod.tsx — havola QR kodi (21/#16): qrcode.react 4.2.0,
// SVG React elementlari (innerHTML yo'q — Trusted Types bilan
// ishlaydi). Alohida chunk: faqat «Ulashish» ochilganda
// yuklanadi. O'lchov (kutubxonalar-21): qrcode.react +6.0 KB,
// uqr +3.9 (SVG satr → blob: rasm), qrcode +8.7
import { QRCodeSVG } from "qrcode.react";

export default function QrKod({ havola }: { havola: string }) {
  return (
    <QRCodeSVG
      id="qr-kod"
      value={havola}
      size={160}
      marginSize={2}
      level="M"
      title="Vazifa havolasining QR kodi"
      role="img"
    />
  );
}

export default — lazy(() => import("./QrKod.tsx")) shuni kutadi.

7.2 Havola: useHref va basename

VazifaUlashish.tsx dagi eng nozik qator — havolani yasash:

tsx
  const havola = new URL(useHref(`/vazifa/${id}`), location.origin)
    .href;

/vazifa/2 ni o'zingiz yozsangiz, ikki narsa yo'qoladi: GitHub Pages'dagi papka (/vazifalar/) va til (/ru/) — i18n II darsida ular router basename iga kirgan. useHref — router'ning o'zidan to'liq yo'l: /vazifalar/ru/vazifa/2. new URL(…, location.origin).href — domen bilan to'liq manzil: telefonga aynan shu kerak.

Nusxalash tugmasi Clipboard API bilan, xatosi ham o'ylangan:

tsx
  async function nusxala() {
    try {
      await navigator.clipboard.writeText(havola);
      setXabar("Havola nusxalandi.");
    } catch {
      // Ruxsat berilmagan yoki xavfsiz kontekst emas —
      // havola ko'rinib turibdi
      setXabar("Nusxalab bo'lmadi — havolani belgilab oling.");
    }
  }

Va halol cheklov — kanon komponenti ichida yozilgan: "Ro'yxat shu brauzerda: boshqa qurilmada o'sha qurilmaning ro'yxati ochiladi." Kirish (auth) yo'q — telefon o'z ro'yxatini ochadi, kompyuterdagini emas. Bu TEXNIK-QARZ 64, 28-qismda haqiqiy kirish (Ro'yxat va login oqimi) bilan yechiladi.

7.3 Natija

e2e-21 — 47 ta, QR'ga oidlari:

text
✅ yopiq: QR chunk yuklanmagan, havola to'liq: [false,"http://127.0.0.1:5718/vazifa/1"]
✅ ochildi: QR (SVG, role=img, nomi), 160 px, chunk keyin yuklandi: ["svg","img","Vazifa havolasining QR kodi",160,true]
✅ QR chunk — ochilgandan keyin: true
✅ nusxalash: xabar, clipboard'da havola: ["Havola nusxalandi.","http://127.0.0.1:5718/vazifa/1"]
✅ QR: CSP buzilishi yo'q: []
✅ Pages/ru: havola /vazifalar/ru/vazifa/2: "/vazifalar/ru/vazifa/2"

Birinchi va uchinchi qator — kech yuklash isboti: yopiq holatda QR chunk'i tarmoqda yo'q, ochilgandan keyin keldi. Oxirgisi — useHref GitHub Pages va rus tilida to'g'ri yo'l berdi.

Narx: QR chunk'i — 6.1 KB gzip (faqat ochilganda). Birinchi yuklash — 222.2 → 222.5 KB (+0.3: VazifaUlashish va lazy chaqiruvi). axe — 0, yangi ko'rinish «ulashish ochiq (QR kod)» bilan. node:test 233, Vitest 65 — o'zgarmadi (yangi sof funksiya yo'q, xulq e2e'da).

bash
git add -A
git commit

Commit (kanon): feat: vazifa havolasi — QR kod (qrcode.react, kech) va nusxalash.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
telefon QR'ni o'qimaydi havola juda uzun, kod zich qisqa havola, M daraja
logoli QR o'qilmaydi daraja L/M yoki logo katta level="H", logo ≤ 1/5, excavate
qorong'i temada o'qilmaydi teskari ranglar yoki fon shaffof doim oq fon, qora katak
QR chunk sahifa bilan yuklandi open && shartisiz details ichida ochilganda chizish
GitHub Pages'da havola 404 /vazifa/2 qo'lda, basename yo'q useHref
kamera chirog'i o'chmaydi track.stop() yo'q tozalash funksiyasida
navigator.mediaDevices undefined http:// (xavfsiz emas) HTTPS yoki localhost
requires 'TrustedHTML' html5-qrcode innerHTML boshqa kutubxona yoki BarcodeDetector

9. Mashqlar

Mashqlar kurs/mashqlar/21/16-qr-kod/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.

1-mashq (oson): bo'sh joylarni to'ldiring

  • 1-versiyali QR kod ×21 katak
  • Logo qo'yilganda kerak bo'ladigan daraja: level=""
  • Kamera faqat yoki localhost da ishlaydi
  • Kamera oqimini to'xtatadigan metod: track.()
  • O'zbekistonning EAN-13 prefiksi:
Yechim
  • 21 — har keyingi versiya +4: 2-versiya 25×25.
  • H — 30% gacha buzilish tiklanadi, logo shu zaxiradan foydalanadi.
  • HTTPS — xavfsiz kontekst; aks holda navigator.mediaDevices yo'q.
  • stop — har trek uchun; usiz kamera yoniq qoladi.
  • 478 — GS1 O'zbekiston prefiksi.

2-mashq (o'rta): mehmonlar Wi-Fi QR'i

«Bahor» mehmonlari uchun Wi-Fi QR: telefon uni skanerlasa, tarmoqqa o'zi ulanadi. Format: WIFI:T:WPA;S:<nom>;P:<parol>;;. Nom va parolda \, ;, ,, : va " belgilari oldiga \ qo'yiladi. wifiText(ssid, password) funksiyasini yozing va QR chizing (title — «Wi-Fi: »). Sinov: tarmoq Bahor;Mehmon, parol osh:35000. Konsolga QR ichidagi matnni chiqaring.

Ishora: belgilarni qochirish — 14-darsdagi pdfString kabi replace(/[\\;,:"]/g, "\\$&").

Yechim
jsx
import { QRCodeSVG } from "qrcode.react";

const escapeWifi = (s) => s.replace(/[\\;,:"]/g, "\\$&");

function wifiText(ssid, password) {
  const s = escapeWifi(ssid);
  const p = escapeWifi(password);
  return `WIFI:T:WPA;S:${s};P:${p};;`;
}

export default function App() {
  const ssid = "Bahor;Mehmon";
  const text = wifiText(ssid, "osh:35000");
  console.log(text);
  return (
    <figure>
      <QRCodeSVG value={text} level="M" title={`Wi-Fi: ${ssid}`} />
      <figcaption>Tarmoq: {ssid}</figcaption>
    </figure>
  );
}

Konsolda:

text
WIFI:T:WPA;S:Bahor\;Mehmon;P:osh\:35000;;

Ekranda:

text
Wi-Fi: Bahor;Mehmon
Tarmoq: Bahor;Mehmon

Qochirishsiz S:Bahor;Mehmon dagi ; maydonni tugatardi: telefon tarmoq nomini «Bahor» deb, «Mehmon» ni esa tushunarsiz maydon deb o'qirdi. Parol QR'da ochiq — bu faqat mehmonlar tarmog'i uchun maqbul (hujumchi nigohidagi "QR'ga sir yozmang" qoidasi: ishchi tarmoq paroli emas).

3-mashq (qiyin): skanerlangan shtrix-kodni tekshirish

Ombor skaneri scanned qatorlarini beradi. checkEan13(code) funksiyasini yozing — u obyekt qaytarsin:

  1. 13 ta raqam bo'lmasa — { ok: false, reason: "13 ta raqam emas" }.
  2. Nazorat raqami mos kelmasa — { ok: false, reason: "nazorat raqami noto'g'ri" }.
  3. To'g'ri bo'lsa — { ok: true, uz: true/false } (uz — 478 bilan boshlanadimi).

Sinov: 4006381333931, 4781234567892, 4781234567893, 47812345.

Ishora: raqamlar — /^\d{13}$/ (RegExp asoslari); nazorat — «Shtrix-kod: EAN-13» bo'limidagi ean13CheckDigit(code.slice(0, 12)).

Yechim
js
function ean13CheckDigit(first12) {
  const sum = [...first12].reduce((total, digit, i) => {
    const weight = i % 2 === 0 ? 1 : 3;
    return total + Number(digit) * weight;
  }, 0);
  return (10 - (sum % 10)) % 10;
}

function checkEan13(code) {
  if (!/^\d{13}$/.test(code)) {
    return { ok: false, reason: "13 ta raqam emas" };
  }
  if (ean13CheckDigit(code.slice(0, 12)) !== Number(code[12])) {
    return { ok: false, reason: "nazorat raqami noto'g'ri" };
  }
  return { ok: true, uz: code.startsWith("478") };
}

const scanned = [
  "4006381333931",
  "4781234567892",
  "4781234567893",
  "47812345",
];
for (const code of scanned) console.log(code, checkEan13(code));

Konsolda:

text
4006381333931 { ok: true, uz: false }
4781234567892 { ok: true, uz: true }
4781234567893 { ok: false, reason: "nazorat raqami noto'g'ri" }
47812345 { ok: false, reason: '13 ta raqam emas' }

Uchinchi kod ikkinchisidan faqat oxirgi raqam bilan farq qiladi — nazorat raqami buni ushladi. Prefiks mahsulot qayerda ro'yxatdan o'tganini bildiradi, qayerda ishlab chiqarilganini emas. /^\d{13}$/ — ^ va $ siz "13 raqam bor" emas, "faqat 13 raqam" tekshiriladi.

4-mashq: Vazifalar qadami

feat/qr branch'ida «Vazifalar qadami» dagi o'zgarishlarni qiling: qrcode.react@4.2.0, ulashish/ papkasidagi uch fayl, VazifaUmumiy.tsx dagi <VazifaUlashish id={vazifa.id} />, QR uchun oq fon.

Yechim

Tekshiruv ro'yxati:

  • Vazifa sahifasi → «Ulashish (QR kod)»: DevTools → Network'da QrKod-….js faqat ochilganda keladi (~6 KB gzip).
  • Telefon kamerasi bilan skanerlang — vazifa havolasi (lokal npm run dev da telefon kompyuterga ulanmaydi — buni deploy qilingan sahifada sinang).
  • Rus tilida (/ru/vazifa/2) havola ham /ru/ bilan; GitHub Pages'da — /vazifalar/ papkasi bilan.
  • «Havolani nusxalash» — e'lon «Havola nusxalandi.».
  • Qorong'i temada QR oq fonda; axe — buzilish yo'q; npm run build — birinchi yuklash ~222.5 KB.

10. Real ishda

  • Restoran va do'konlar — stol QR menyusi, to'lov QR kodlari (O'zbekistonda to'lov ilovalari QR orqali to'lovni keng ishlatadi), chekdagi QR.
  • Login va qurilmalar — "telefon bilan kirish" (Telegram Desktop kabi): QR'da bir martalik, qisqa muddatli va serverda tekshiriladigan kod — 28-qismdagi mavzu.
  • Ombor va logistika — shtrix-kod skanerlari, ko'pincha klaviatura kabi ishlaydigan USB qurilmalar.
  • Intervyu savollari: "QR'ning xatoni tuzatish darajasi nima?", "logoli QR qanday ishlaydi?", "kamerani React'da qanday to'g'ri yopasiz?", "quishing'dan qanday himoyalanasiz?".

Xulosa

  • QR: versiya (21×21 dan, +4), daraja L/M/Q/H (7–30%), chet maydoni; qisqa havola — oddiy kod.
  • qrcode.react (+6.0 KB): QRCodeSVG — React elementlari, Trusted Types bilan muammosiz; title va role="img".
  • Logo — level="H", kichik, excavate; fon doim oq.
  • QR'ni kech yuklang: lazy + details ochilganda; havola yonida matn ham bo'lsin.
  • Skanerlash: HTTPS, ruxsat, BarcodeDetector (hamma joyda emas) yoki kutubxona (57–105 KB, CSP muammolari); tozalashda track.stop().
  • EAN-13 — nazorat raqami; skanerlangan narsani avtomatik ochmang, QR'ga sir yozmang.

Keyingi dars: Fayl yuklab berish: Blob, a[download] va showSaveFilePicker — vazifalar eksportini foydalanuvchi o'zi tanlagan joyga saqlash va yuklab berishning React'dagi naqshlari.

Manbalar

  • ISO/IEC 18004 (QR Code): versiyalar, xatoni tuzatish darajalari, quiet zone
  • qrcode.react 4 — github.com/zpao/qrcode.react (QRCodeSVG, level, marginSize, imageSettings)
  • MDN: Barcode Detection API (brauzer qo'llovi), MediaDevices.getUserMedia(), MediaStreamTrack.stop()
  • ZXing: "Barcode Contents" (WIFI formati) — github.com/zxing/zxing/wiki
  • GS1: EAN-13 nazorat raqami, mamlakat prefikslari — gs1.org
  • Kanon: vazifalar holat 16, natijalar/tekshiruv-16.txt, 16-axe.txt, brauzer-tekshiruv/natija-21-16.txt, natijalar/tajriba/kutubxonalar-21.txt (2026-10-17)
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
QR kod React'da: qrcode.react, logo, kamera bilan skanerlash va shtrix-kod — IlmHamroh