captureOwnerStack đọc Owner Stack hiện tại trong quá trình phát triển và trả về nó dưới dạng một chuỗi nếu có.

const stack = captureOwnerStack();

Tham khảo

captureOwnerStack()

Gọi captureOwnerStack để lấy Owner Stack hiện tại.

import * as React from 'react';

function Component() {
if (process.env.NODE_ENV !== 'production') {
const ownerStack = React.captureOwnerStack();
console.log(ownerStack);
}
}

Tham số

captureOwnerStack không nhận bất kỳ tham số nào.

Giá trị trả về

captureOwnerStack trả về string | null.

Owner Stack có sẵn trong

  • Quá trình render Component
  • Các Effect (ví dụ: useEffect)
  • Các trình xử lý sự kiện của React (ví dụ: <button onClick={...} />)
  • Các trình xử lý lỗi của React (Tùy chọn React Root onCaughtError, onRecoverableErroronUncaughtError)

Nếu không có Owner Stack nào khả dụng, null sẽ được trả về (xem Khắc phục sự cố: Owner Stack là null).

Lưu ý

  • Owner Stack chỉ khả dụng trong quá trình phát triển. captureOwnerStack sẽ luôn trả về null bên ngoài quá trình phát triển.
Tìm hiểu sâu

Owner Stack so với Component Stack

Owner Stack khác với Component Stack có sẵn trong các trình xử lý lỗi của React như errorInfo.componentStack trong onUncaughtError.

Ví dụ: xem xét đoạn mã sau:

import {captureOwnerStack} from 'react';
import {createRoot} from 'react-dom/client';
import App, {Component} from './App.js';
import './styles.css';

createRoot(document.createElement('div'), {
  onUncaughtError: (error, errorInfo) => {
    // Các stack được ghi lại thay vì hiển thị chúng trực tiếp trong UI để
    // làm nổi bật rằng các trình duyệt sẽ áp dụng sourcemap cho các stack đã ghi lại.
    // Lưu ý rằng sourcemapping chỉ được áp dụng trong bảng điều khiển trình duyệt thực chứ không
    // trong bảng điều khiển giả được hiển thị trên trang này.
    // Nhấn "fork" để có thể xem stack đã được sourcemap trong một bảng điều khiển thực.
    console.log(errorInfo.componentStack);
    console.log(captureOwnerStack());
  },
}).render(
  <App>
    <Component label="disabled" />
  </App>
);

SubComponent sẽ ném ra một lỗi. Component Stack của lỗi đó sẽ là

at SubComponent
at fieldset
at Component
at main
at React.Suspense
at App

Tuy nhiên, Owner Stack sẽ chỉ đọc

at Component

Cả App và các component DOM (ví dụ: fieldset) đều không được coi là Owner trong Stack này vì chúng không đóng góp vào việc “tạo” node chứa SubComponent. App và các component DOM chỉ chuyển tiếp node. App chỉ render node children trái ngược với Component, component này đã tạo một node chứa SubComponent thông qua <SubComponent />.

Cả Navigationlegend đều không có trong stack vì nó chỉ là một sibling của một node chứa <SubComponent />.

SubComponent bị bỏ qua vì nó đã là một phần của callstack.

Cách sử dụng

Cải thiện lớp phủ lỗi tùy chỉnh

import { captureOwnerStack } from "react";
import { instrumentedConsoleError } from "./errorOverlay";

const originalConsoleError = console.error;
console.error = function patchedConsoleError(...args) {
originalConsoleError.apply(console, args);
const ownerStack = captureOwnerStack();
onConsoleError({
// Lưu ý rằng trong một ứng dụng thực tế, console.error có thể được
// gọi với nhiều đối số mà bạn nên tính đến.
consoleMessage: args[0],
ownerStack,
});
};

Nếu bạn chặn các lệnh gọi console.error để làm nổi bật chúng trong lớp phủ lỗi, bạn có thể gọi captureOwnerStack để bao gồm Owner Stack.

import { captureOwnerStack } from "react";
import { createRoot } from "react-dom/client";
import App from './App';
import { onConsoleError } from "./errorOverlay";
import './styles.css';

const originalConsoleError = console.error;
console.error = function patchedConsoleError(...args) {
  originalConsoleError.apply(console, args);
  const ownerStack = captureOwnerStack();
  onConsoleError({
    // Lưu ý rằng trong một ứng dụng thực tế, console.error có thể được
    // gọi với nhiều đối số mà bạn nên tính đến.
    consoleMessage: args[0],
    ownerStack,
  });
};

const container = document.getElementById("root");
createRoot(container).render(<App />);

Khắc phục sự cố

Owner Stack là null

Lệnh gọi captureOwnerStack xảy ra bên ngoài một hàm được kiểm soát bởi React, ví dụ: trong một callback setTimeout, sau một lệnh gọi fetch hoặc trong một trình xử lý sự kiện DOM tùy chỉnh. Trong quá trình render, Effects, trình xử lý sự kiện React và trình xử lý lỗi React (ví dụ: hydrateRoot#options.onCaughtError), Owner Stack sẽ khả dụng.

Trong ví dụ dưới đây, việc nhấp vào nút sẽ ghi lại một Owner Stack trống vì captureOwnerStack đã được gọi trong một trình xử lý sự kiện DOM tùy chỉnh. Owner Stack phải được chụp sớm hơn, ví dụ: bằng cách di chuyển lệnh gọi captureOwnerStack vào phần thân Effect.

import {captureOwnerStack, useEffect} from 'react';

export default function App() {
  useEffect(() => {
    // Nên gọi `captureOwnerStack` ở đây.
    function handleEvent() {
      // Gọi nó trong một trình xử lý sự kiện DOM tùy chỉnh là quá muộn.
      // Owner Stack sẽ là `null` tại thời điểm này.
      console.log('Owner Stack: ', captureOwnerStack());
    }

    document.addEventListener('click', handleEvent);

    return () => {
      document.removeEventListener('click', handleEvent);
    }
  })

  return <button>Nhấp vào tôi để thấy rằng Owner Stack không khả dụng trong trình xử lý sự kiện DOM tùy chỉnh</button>;
}

captureOwnerStack không khả dụng

captureOwnerStack chỉ được xuất trong các bản dựng dành cho quá trình phát triển. Nó sẽ là undefined trong các bản dựng production. Nếu captureOwnerStack được sử dụng trong các tệp được đóng gói cho cả production và development, bạn nên truy cập có điều kiện từ một namespace import.

// Không sử dụng named import của `captureOwnerStack` trong các tệp được đóng gói cho development và production.
import {captureOwnerStack} from 'react';
// Sử dụng namespace import thay thế và truy cập `captureOwnerStack` có điều kiện.
import * as React from 'react';

if (process.env.NODE_ENV !== 'production') {
const ownerStack = React.captureOwnerStack();
console.log('Owner Stack', ownerStack);
}