-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RNMobile] Add error boundary components and exception logging #59221
Changes from 11 commits
34221bb
95e9a25
808d2d9
205987e
9d57c27
265b139
ca76b90
5d4be1a
1c9384e
53b2f2e
bc67ebb
3e30aaf
f4bfed0
37348cb
2a519b4
4dece96
12aff79
5f4e208
a746556
35338be
5457c0e
4a6b38b
5e1daea
260cb3a
a598b77
c017e12
7c18727
363cb12
294ac99
7dadd4a
2002dcf
cfaf638
49f32e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Component } from '@wordpress/element'; | ||
import { logException } from '@wordpress/react-native-bridge'; | ||
|
||
class BlockCrashBoundary extends Component { | ||
constructor() { | ||
super( ...arguments ); | ||
|
||
this.state = { | ||
error: null, | ||
}; | ||
} | ||
|
||
static getDerivedStateFromError( error ) { | ||
return { error }; | ||
} | ||
|
||
componentDidCatch( error ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's more information about this component function: https://react.dev/reference/react/Component#componentdidcatch |
||
const { blockName } = this.props; | ||
|
||
logException( error, { | ||
context: { | ||
component_stack: error.componentStack, | ||
error_boundary_level: 'block', | ||
block_name: blockName, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As additional context to debug the exception, we'll attach at what level the exception happened and the block's name. |
||
}, | ||
} ); | ||
} | ||
|
||
render() { | ||
const { error } = this.state; | ||
if ( ! error ) { | ||
return this.props.children; | ||
} | ||
|
||
return this.props.fallback; | ||
} | ||
} | ||
|
||
export default BlockCrashBoundary; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import Warning from '../warning'; | ||
|
||
const warning = ( | ||
<Warning | ||
message={ __( | ||
'This block has encountered an error and cannot be previewed.' | ||
) } | ||
/> | ||
); | ||
|
||
export default () => warning; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Component } from '@wordpress/element'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { Button } from '@wordpress/components'; | ||
import { select } from '@wordpress/data'; | ||
import { Warning } from '@wordpress/block-editor'; | ||
import { useCopyToClipboard } from '@wordpress/compose'; | ||
import { logException } from '@wordpress/react-native-bridge'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as editorStore } from '../../store'; | ||
|
||
function getContent() { | ||
try { | ||
// While `select` in a component is generally discouraged, it is | ||
// used here because it (a) reduces the chance of data loss in the | ||
// case of additional errors by performing a direct retrieval and | ||
// (b) avoids the performance cost associated with unnecessary | ||
// content serialization throughout the lifetime of a non-erroring | ||
// application. | ||
return select( editorStore ).getEditedPostContent(); | ||
} catch ( error ) {} | ||
} | ||
|
||
function CopyButton( { text, children } ) { | ||
const ref = useCopyToClipboard( text ); | ||
return ( | ||
<Button variant="secondary" ref={ ref }> | ||
{ children } | ||
</Button> | ||
); | ||
} | ||
|
||
class ErrorBoundary extends Component { | ||
constructor() { | ||
super( ...arguments ); | ||
|
||
this.state = { | ||
error: null, | ||
}; | ||
} | ||
|
||
componentDidCatch( error ) { | ||
logException( error, { | ||
context: { | ||
component_stack: error.componentStack, | ||
error_boundary_level: 'editor', | ||
}, | ||
} ); | ||
} | ||
|
||
static getDerivedStateFromError( error ) { | ||
return { error }; | ||
} | ||
|
||
render() { | ||
const { error } = this.state; | ||
if ( ! error ) { | ||
return this.props.children; | ||
} | ||
|
||
const actions = [ | ||
<CopyButton key="copy-post" text={ getContent }> | ||
{ __( 'Copy Post Text' ) } | ||
</CopyButton>, | ||
<CopyButton key="copy-error" text={ error.stack }> | ||
{ __( 'Copy Error' ) } | ||
</CopyButton>, | ||
]; | ||
fluiddot marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return ( | ||
<Warning | ||
actions={ actions } | ||
message={ __( | ||
'The editor has encountered an unexpected error.' | ||
) } | ||
/> | ||
); | ||
} | ||
} | ||
|
||
export default ErrorBoundary; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's more information about this static function: https://react.dev/reference/react/Component#static-getderivedstatefromerror