React 18 và React 19
Cài @belvador/react cho ứng dụng React chạy trên trình duyệt (Vite, SPA), với cách nối riêng cho React 18 và React 19.
Trong bài này
Dùng @belvador/react cho ứng dụng React render trên trình duyệt — Vite, Create React App hoặc dạng SPA khác. Gói này có mọi thứ của @belvador/browser, cộng thêm error boundary và root hook của React 19. Ứng dụng Lovable và TanStack Start dùng TanStack Start.
Trước khi bắt đầu#
Một project có nền tảng React (Vite / SPA) và DSN của nó.
React 18 hoặc React 19. Kiểm tra bản đang dùng:
npm ls react.
1. Cài đặt#
npm install @belvador/react@0.6.12. Khởi tạo#
Tạo src/instrument.ts. File này khởi động Belvador:
import { init } from "@belvador/react";init({ dsn: "https://<public-key>@ingest.belvador.dev/<project-id>", release: import.meta.env.VITE_APP_VERSION, // your build or commit id environment: import.meta.env.MODE,});3. Import đầu tiên — React 18#
Đặt ./instrument là dòng import đầu tiên của src/main.tsx. Các import chạy trước phần còn lại của file, nên một lệnh init viết bên dưới import App sẽ không bao giờ chạy nếu một module của App lỗi lúc đang nạp — ví dụ thiếu biến môi trường. Trang trắng và không có lỗi nào được báo. Bản này chạy được với React 18 và 19. ErrorBoundary báo lỗi render (kèm component stack) và hiện nội dung thay thế thay vì trang trắng.
import "./instrument"; // first line: starts Belvador before App's modules loadimport { createRoot } from "react-dom/client";import { ErrorBoundary } from "@belvador/react";import App from "./App";const root = document.getElementById("root");if (!root) throw new Error("Root element missing");createRoot(root).render( <ErrorBoundary fallback={<p>Something went wrong.</p>}> <App /> </ErrorBoundary>,);3. Import đầu tiên — React 19#
React 19 tự xử lý nhiều lỗi và không để chúng tới window.onerror. Truyền reactErrorHandler() vào ba tuỳ chọn của root để Belvador thấy các lỗi đó. Các tuỳ chọn này không có trong React 18 — ở React 18 dùng bản phía trên.
import "./instrument"; // first line: starts Belvador before App's modules loadimport { createRoot } from "react-dom/client";import { ErrorBoundary, reactErrorHandler } from "@belvador/react";import App from "./App";const root = document.getElementById("root");if (!root) throw new Error("Root element missing");createRoot(root, { onUncaughtError: reactErrorHandler(), onCaughtError: reactErrorHandler(), onRecoverableError: reactErrorHandler(),}).render( <ErrorBoundary fallback={<p>Something went wrong.</p>}> <App /> </ErrorBoundary>,);| Tuỳ chọn của root | Báo lỗi gì |
|---|---|
onUncaughtError | Lỗi không error boundary nào bắt |
onCaughtError | Lỗi đã bị error boundary bắt và hiện nội dung thay thế |
onRecoverableError | Lỗi React tự phục hồi được, ví dụ lệch dữ liệu khi hydrate |
reactErrorHandler nhận một callback tuỳ chọn, chạy sau khi đã báo: reactErrorHandler((error, errorInfo, eventId) => { … }).
4. Cho phép địa chỉ nhận lỗi trong CSP#
connect-src 'self' https://ingest.belvador.dev;Gộp dòng này vào connect-src hiện có; đừng thay cả chính sách.
Error boundary cho từng phần của trang#
Bọc những phần dễ lỗi của giao diện để một widget hỏng không kéo sập cả trang:
import { ErrorBoundary, withErrorBoundary } from "@belvador/react";export function Dashboard() { return ( <ErrorBoundary fallback={({ resetError }) => ( <div role="alert"> <p>Biểu đồ này chưa tải được.</p> <button onClick={resetError}>Thử lại</button> </div> )} > <RevenueChart /> </ErrorBoundary> );}// Hoặc bọc một component một lần:export const SafeRevenueChart = withErrorBoundary(RevenueChart, { fallback: <p>Biểu đồ này chưa tải được.</p>,});ErrorBoundary báo mỗi lỗi render một lần và hiện fallback. Hộp thoại xin phản hồi người dùng mà một số SDK có thì không có ở đây: nó sẽ phải tải script từ mạng.
Báo những lỗi bạn đã xử lý#
Mọi thứ của @belvador/browser cũng được export ở đây:
import { captureException, setUser } from "@belvador/react";setUser({ id: user.id });try { await importCsv(file);} catch (error) { captureException(error); setStatus("failed");}Kiểm tra#
Thêm tạm một nút, bấm thử rồi mở project trong Belvador:
function Crash(): never { throw new Error("Belvador React test");}export function TestButton() { const [crash, setCrash] = useState(false); return crash ? <Crash /> : <button onClick={() => setCrash(true)}>Gửi lỗi thử</button>;}Issue hiện component stack trong mục Ngữ cảnh. Nhớ xoá nút sau khi thử.
Giới hạn cần biết#
Hàm xử lý sự kiện (
onClick, …) và code bất đồng bộ không nằm trong phạm vi của error boundary — đây là quy tắc của React. Lỗi ở đó mà không ai bắt vẫn tới Belvador qua bộ bắt lỗi toàn cục; lỗi bạn tự bắt thì cầncaptureException.Các framework render phía máy chủ khác ngoài TanStack Start không nằm trong phạm vi cài đặt của gói này.
Bài viết về chủ đề này
Tất cả bài viết- Error boundary của React và lỗi async: thí nghiệm bắt được gìError boundary của React 19 bắt lỗi nào, lỗi nào tới onCaughtError, onUncaughtError hay window, và vì sao startTransition độc lập lại cư xử khác.
- Source map trên production với Vite: mỗi cấu hình thực sự đưa gì vào bản buildSo sánh sourcemap false, true và hidden của Vite trên một bản build: file nào được tạo, stack frame hiện gì, và cách có stack dễ đọc mà không lộ map.
- Giám sát ứng dụng vibe coding: thứ gì hỏng sau khi publishApp vibe coding hỏng gì sau khi publish, vì sao uptime check vẫn thấy 200 OK, và ba lớp kiểm tra bắt được lỗi. Thử thật trên năm bản build hỏng.
Thấy chỗ sai hoặc thiếu? Gửi cho chúng tôi: hello@belvador.dev