Tại sao thành phần này được hiển thị sau khi ném lỗi?


8

Tôi hiện đang theo dõi cùng với tài liệu React JS và tôi đã gặp phải một vấn đề với các ranh giới lỗi không hoạt động như mong đợi. Tôi đã thử sao chép ví dụ được hiển thị trong CodePen do các tài liệu cung cấp và một vài ví dụ đơn giản khác mà tôi đã tìm thấy trên internet, tuy nhiên nó không hoạt động giống như tôi trong bản demo và tôi đang vật lộn để hiểu tại sao.

Vấn đề chính xác là lỗi được ném hai lần vì thành phần BuggyCorer được hiển thị thêm thời gian. Tôi không hiểu tại sao thành phần này lại xuất hiện lần thứ hai.

Xin hãy xem ví dụ tối thiểu này.

import React, { Component } from 'react';

function App() {
  return (
    <ErrorHandler>
      <BuggyCounter />
    </ErrorHandler>
  );
}

class ErrorHandler extends Component {
  constructor(props) {
    super(props);
    this.state = {
      error: false,
      errorInfo: null
    }
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ error, errorInfo });
  }

  render() {
    console.log('rendering ErrorHandler. ' + (this.state.error ? "error" : "no error"));
    if(this.state.error) {
      return <p>Error</p>
    }
    return this.props.children;
  }
}

class BuggyCounter extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
  }

  handleClick = () => {
    this.setState(({ counter }) => ({
      counter: counter + 1
    }));
  };

  render() {
    console.log('rendering BuggyCounter. count: ' + this.state.counter);
    if (this.state.counter === 5) {
      throw new Error('I crashed!');
    }
    return <h1 onClick={this.handleClick}>{this.state.counter}</h1>
  }
}

export default App;

Thành phần BuggyCorer đang được thay thế bằng <p>thẻ hiển thị Lỗi Lỗi (đây là hiệu ứng mong muốn), nhưng chỉ trong chốc lát. Ngay sau đó, trang lỗi mặc định đang được hiển thị, đánh bại mục đích của Ranh giới Lỗi.

Đây là bảng điều khiển của tôi:

lỗi và thông báo gỡ lỗi của tôi

Tôi sẽ đánh giá cao bất kỳ thông tin bạn có thể cung cấp về chủ đề này.

Giải quyết tạm thời:

Đây không phải là câu trả lời cho câu hỏi của tôi, nhưng một cách để ngăn chặn kết xuất không cần thiết là ném lỗi từ componentDidUpdatethay vì render.

  render() {
    console.log('rendering BuggyCounter. count: ' + this.state.counter);
    return <h1 onClick={this.handleClick}>{this.state.counter}</h1>
  }

  componentDidUpdate() {
    if(this.state.counter === 5)
      throw new Error('I crashed');
  }

Câu hỏi hay, tôi không biết tại sao, nhưng có lẽ khi một thành phần gây ra lỗi, nó sẽ tự phục hồi? Không có manh mối.
Vencovsky

2
Tôi không thể sao chép lỗi trong mã hộp cát và hộp.io / s / urct
Prasanna

1
Một điểm kỳ lạ để xem xét ở đây là nếu bạn thêm một bản ghi trước khi ném lỗi và trong đó componentDidCatchbạn sẽ thấy rằng nó ném lỗi hai lần, nhưng nó chỉ truyền vào componenDidCatchmột lần.
Vencovsky

@Prasanna giống nhau ở đây
Vencovsky

Nếu ai đó muốn xem phản hồi từ phản ứng github.com/facebook/react/issues/17966
Vencovsky

Câu trả lời:


3

Chỉnh sửa 2:

Chà, vấn đề là ở phiên bản phản ứng 16.12.0, nếu bạn đổi nó thành 16.0.0, nó sẽ không được đăng ký lại hai lần. Bạn có thể kiểm tra điều này trong hộp mã này bằng cách thay đổi phiên bản phản ứng.

Đây là một vấn đề tốt để thêm vào phản ứng github.

Có lẽ là một cái gì đó nội bộ trong phản ứng mã lõi. Vì vậy, tùy thuộc vào phiên bản của bạn, nó sẽ hiển thị hai lần hoặc chỉ một lần.


Biên tập:

Tại sao các rerenders thành phần? Không ý kiến.

Nhưng, trang lỗi chỉ được hiển thị trong chế độ phát triển , vì vậy bạn componentDidCatchđang làm việc.


Câu trả lời cũ / xấu

Thành phần BuggyCorer đang được thay thế bằng <p>thẻ hiển thị Lỗi Lỗi (đây là hiệu ứng mong muốn), nhưng chỉ trong chốc lát. Ngay sau đó, trang lỗi mặc định đang được hiển thị, đánh bại mục đích của Ranh giới Lỗi.

Phần only for a momentkhông đúng. Trang lỗi chỉ tình cờ phát triển, nếu bạn chạy nó trong chế độ sản xuất, nó sẽ không được hiển thị.

Và như bạn có thể thấy trong ví dụ của tôi , nếu bạn đóng trang lỗi, bạn sẽ thấy thành phần lỗi.

Điều này được giải thích trong câu trả lời này .

Vì vậy, trong phiên bản demo được cung cấp bởi các tài liệu phản ứng, nó không hiển thị trang lỗi do cấu hình của nó chứ không phải mã tự nó. Mã của bạn đang hoạt động tốt, chỉ cần đóng trang lỗi và xem kết quả.


Các BuggyCounterphải bị trả lại gấp đôi khi state.counter === 5vì các chương trình log "Rendering BuggyCounter đếm:. 5" hai lần. Tôi tin rằng bạn đã giải thích lý do tại sao ErrorHandlerđược kết xuất thêm một thời gian.
Anthony Yershov

Tôi vẫn chưa rõ tại sao lại BuggyCounterthực hiện kết xuất bổ sung sau khi gặp lỗi.
Anthony Yershov

1
@AnthonyYershov đó là vì bạn đang thay đổi trạng thái của mình componentDidCatch. Thay đổi trạng thái sẽ đăng ký lại thành phần của bạn.
Prasanna

@Prasanna có chính xác. Đó là lý do tại sao ErrorHandlerđược nhận lại một lần nữa. Đó không phải là câu hỏi của tôi. Nếu bạn nhìn vào nhật ký, BuggyCountersẽ được kết xuất thêm một thời gian trước khi ErrorHandlerđược kết xuất lại do thay đổi trạng thái.
Anthony Yershov

1
Tôi có thể xác nhận rằng vấn đề này không tồn tại trong React 16.0.0 cảm ơn bạn về thông tin này và đã nêu ra vấn đề này trên github phản ứng.
Anthony Yershov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.