javascript - React `componentDidCatch` 未被调用但需要处理错误?
<p><p>我正在尝试使用 React 的 <code>componentDidCatch</code> 方法来捕获导致我的 Cordova iOS 应用程序崩溃的错误。它似乎可以防止崩溃,但该方法从未被调用,所以我不知道是什么导致了问题。</p>
<p>我的组件:</p>
<pre><code>import styled from 'styled-components';
import { View, observable } from 'shared/View';
import { Player } from 'video-react';
import SpinnerOverlay from 'shared/components/SpinnerOverlay';
import * as Icons from 'shared/components/Icons';
import fs from 'fileSystem';
export default class VideoOverlay extends View {
@observable ready = false;
handlePlayerStateChange = (state, prevState) => {
const { onClose } = this.props;
if(state.paused && !prevState.paused && onClose) {
try {
onClose();
} catch(error) {
console.log('--- onClose error', error);
}
}
};
handlePlayerRef = (player) => {
player.subscribeToStateChange(this.handlePlayerStateChange);
player.play();
};
async componentDidMount() {
try {
const { mediaFile } = this.props;
await mediaFile.download(fs);
this.ready = true;
} catch(error) {
console.log('--- SHIT', error);
}
}
componentDidCatch(error) {
// Needed because `Player` throws an error when unmounting.
// This method doesn't get called (not sure why), but without this method,
// the app crashes when a video is closed.
console.log('Caught', error);
}
render() {
const { ready } = this;
const { mediaFile } = this.props;
const src = ready && mediaFile.fileSrc;
return (
<React.Fragment>
<SpinnerOverlay visible/>
{ready &&
<Player ref={this.handlePlayerRef}>
<source src={src}/>
</Player>
}
</React.Fragment>
);
}
}
</code></pre>
<p>组件工作正常,但卸载时,它始终抛出此错误:</p>
<pre><code>2018-02-22 12:52:19.706530-0800 App ERROR: The above error occurred in the <Player> component:
in Player (created by Component)
in Component (created by Component)
in div (created by Screen)
in Screen (created by Component)
in Component (created by inject-Component-with-store)
in inject-Component-with-store (created by Route)
in Route (created by Component)
in Switch (created by Component)
in Component (created by inject-Component-with-store)
in inject-Component-with-store (created by Route)
in Route (created by Component)
in Component (created by Route)
in Route (created by withRouter(Component))
in withRouter(Component) (created by inject-withRouter(Component)-with-api)
in inject-withRouter(Component)-with-api (created by Component)
in Switch (created by Component)
in div (created by App__Root)
in App__Root (created by Component)
in Component (created by Route)
in Route (created by withRouter(Component))
in withRouter(Component)
in Router (created by HashRouter)
in HashRouter
in Provider
</code></pre>
<p>此错误出现在 XCode 控制台中,上面没有错误。 <code>componentDidCatch</code> 中的 <code>console.log</code> 永远不会运行。 <code>componentDidMount</code> 和 <code>handlePlayerStateChange</code> 中的 <code>catch</code>block 也永远不会到达。</p>
<p>最奇怪的是,如果我删除 <code>componentDidCatch</code>,应用程序会因上述错误而崩溃,因此 <code>componentDidCatch</code> 似乎在做<em>某事</em> ;只是没有让我真正处理错误。</p>
<p>另外,我无法在浏览器中重现此问题,因为此组件仅适用于 iOS(此组件利用 iOS 自动全屏自动播放视频)。</p></p>
<br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
<p><p>问题是 <code>componentDidCatch</code> 不会捕获事件处理程序错误,就像您的 <code>handlePlayerRef</code> 方法中的处理程序会发生的错误一样。那是因为这些类型的错误不会在组件的渲染过程中发生,这是 <code>didCatch</code> 的预期目的。</p>
<p>例如,这不会被 <code>didCatch</code> 正确捕获和记录:</p>
<pre><code>class MyComponent extends Component {
componentDidCatch() {
console.log('whats wrong?')
}
onButtonClick() {
//errors emerging here
}
render() {
return (
<button onClick={this.onButtonClick}>Click</button>
);
}
}
</code></pre>
<p>如果您需要捕获此类错误,请使用 <code>handlePlayerRef</code> 中的常规 try/catchblock 。</p>
<pre><code>handlerPlayerRef() {
try {
player.subscribeToStateChange(this.handlePlayerStateChange);
player.play();
} catch () {
console.error('Something wrong happened');
}
}
</code></pre>
<p>此外,通常最好将组件渲染错误与组件功能分离,因为它往往会产生难以调试的神秘错误。</p>
<p>您是否尝试过构建一个 ErrorBoundary 组件来包裹您的 VideoOverlay 类?这样做并将其呈现条件为不存在错误:</p>
<pre><code>class ErrorBoundary extends React.Component {
componentDidCatch(err) {
this.setState({
hasError: true
});
}
render() {
return this.state.hasError
?<h2>Oh noes! Something went wrong.</h2>
:this.props.children
}
}
</code></pre>
<p>现在您可以只提供 VideoOverlay 作为 ErrorBoundary 的子级:</p>
<pre><code><ErrorBoundary>
<VideoOverlay />
</ErrorBoundary>
</code></pre>
<p>详细阅读 <a href="https://reactjs.org/docs/error-boundaries.html" rel="noreferrer noopener nofollow">here</a> </p></p>
<p style="font-size: 20px;">关于javascript - React`componentDidCatch` 未被调用但需要处理错误?,我们在Stack Overflow上找到一个类似的问题:
<a href="https://stackoverflow.com/questions/48937080/" rel="noreferrer noopener nofollow" style="color: red;">
https://stackoverflow.com/questions/48937080/
</a>
</p>
页:
[1]