ReactJS - 静态 getDerivedStateFromError() 方法



当一个组件或其子组件在 React 中渲染时遇到错误时,可能很难处理该错误并将其传达给用户。getDerivedStateFromError 函数在此处生效。在本教程中,我们将了解它是如何工作的。

在 React 中,我们可以在类组件中定义一个名为 getDerivedStateFromError 的特定函数。当一个子组件,无论它在层次结构中有多深,遇到错误,React 都会调用这个函数。我们可以显示详细的错误消息,而不是显示空白或损坏的用户界面。

语法


static getDerivedStateFromError(error)

参数

  • error − getDerivedStateFromError中的error参数提供错误信息。它通常是一个 Error 实例,但它可以是另一种类型。

返回值

该方法应返回更新的状态,并显示组件应显示错误消息。

例子

示例 1

创建一个使用 getDerivedStateFromError 函数的基本 React 应用需要创建一个具有错误限制的简单类组件。下面是一个使用 getDerivedStateFromError() 函数的小例子 -


import React, { Component } from 'react';

class ErrorBoundary extends Component {
	 	constructor(props) {
	 	 	 super(props);
	 	 	 this.state = { hasError: false, errorMessage: '' };
	 	} 		
	 	static getDerivedStateFromError(error) {
	 	 	 return { hasError: true, errorMessage: error.message };
	 	} 		
	 	componentDidCatch(error, errorInfo) {
	 	 	 // Log the error here
	 	 	 console.error(error, errorInfo);
	 	} 		
	 	render() {
	 	if (this.state.hasError) {
	 	 	 return (
	 	 	 	 	<div>
	 	 	 	 	 	 <h2>Something went wrong</h2>
	 	 	 	 	 	 <p>{this.state.errorMessage}</p>
	 	 	 	 	</div>
	 	 	 );
	 	} 		
	 	return this.props.children;
	 	}
}

class App extends Component {
	 	render() {
	 	 	 return (
	 	 	 	 	<div>
	 	 	 	 	 	 <h1>Simple Error Handling App</h1>
	 	 	 	 	 	 <ErrorBoundary>
	 	 	 	 	 	 	 	{/* error in a child component */}
	 	 	 	 	 	 	 	<ChildComponent />
	 	 	 	 	 	 </ErrorBoundary>
	 	 	 	 	</div>
	 	 	 );
	 	}
}
class ChildComponent extends Component {
	 	componentDidMount() {
	 	 	 // Simulate an error
	 	 	 throw new Error('Error in ChildComponent');
	 	}
	 	
	 	render() {
	 	 	 return <p>This is a child component</p>;
	 	}
}

export default App;

输出

简单的错误处理应用程序

此示例演示如何使用 getDerivedStateFromError componentDidCatch 函数的 ErrorBoundary 类组件制作一个简单的 React 应用。为了显示错误处理,ChildComponent 故意在其 componentDidMount 生命周期函数中引发错误。

当我们启动应用程序时,我们将在用户界面中收到一条错误消息。我们可以修改和扩展此代码以满足我们自己的要求。

示例 2

这是另一个示例,借助 React 组件中的 getDerivedStateFromError 函数进行错误处理。这一次,我们将模拟渲染图像的子组件中的错误 -


import React, { Component } from 'react';
import './App.css';

class ErrorBoundary extends Component {
	 	constructor(props) {
	 	 	 super(props);
	 	 	 this.state = { hasError: false, errorMessage: '' };
	 	} 		
	 	static getDerivedStateFromError(error) {
	 	 	 return { hasError: true, errorMessage: error.message };
	 	} 		
	 	componentDidCatch(error, errorInfo) {
	 	 	 // Log the error here
	 	 	 console.error(error, errorInfo);
	 	} 		
	 	render() {
	 	if (this.state.hasError) {
	 	 	 return (
	 	 	 	 	<div>
	 	 	 	 	 	 <h2>Something went wrong</h2>
	 	 	 	 	 	 <p>{this.state.errorMessage}</p>
	 	 	 	 	</div>
	 	 	 );
	 	}
	 	
	 	return this.props.children;
	 	}
}
class App extends Component {
	 	render() {
	 	 	 return (
	 	 	 	 	<div className='App'>
	 	 	 	 	 	 <h1>Error Handling with Images</h1>
	 	 	 	 	 	 <ErrorBoundary>
	 	 	 	 	 	 	 	{/* error in a child component */}
	 	 	 	 	 	 	 	<ImageComponent />
	 	 	 	 	 	 </ErrorBoundary>
	 	 	 	 	</div>
	 	 	 );
	 	}
}
class ImageComponent extends Component {
	 	state = {
	 	 	 hasError: false,
	 	};
	 	
	 	// Error occur by attempting to load an invalid image
	 	loadImage = () => {
	 	 	 const img = new Image();
	 	 	 img.src = 'image-url1';
	 	 	 img.onload = () => {
	 	 	 	 	// This will not execute because the image source is invalid
	 	 	 };
	 	 	 img.onerror = () => {
	 	 	 	 	// Error and catch it in the ErrorBoundary
	 	 	 	 	this.setState({ hasError: true });
	 	 	 };
	 	}; 		
	 	componentDidMount() {
	 	 	 this.loadImage();
	 	}
	 	
	 	render() {
	 	 	 if (this.state.hasError) {
	 	 	 	 	// Render an alternative content when an error occurs
	 	 	 	 	return <p>Failed to load the image</p>;
	 	 	 }
	 	 		
	 	 	 return <img src="image-url2" alt="A Valid Image" />;
	 	}
}

export default App;

输出

图像的错误处理

在此示例中,ImageComponent 组件尝试加载具有无效 URL 的图像,这会触发错误。ErrorBoundary 捕获错误,我们可以在发生错误时自定义组件的呈现。

示例 3

在此示例中,我们将在从 API 获取数据的子组件中创建一个 Bug。getDerivedStateFromError 函数将用于管理错误并显示用户友好的消息。代码如下 -


import React, { Component } from 'react';
import './App.css';

class ErrorBoundary extends Component {
	 	constructor(props) {
	 	 	 super(props);
	 	 	 this.state = { hasError: false, errorMessage: '' };
	 	} 		
	 	static getDerivedStateFromError(error) {
	 	 	 return { hasError: true, errorMessage: error.message };
	 	} 		
	 	componentDidCatch(error, errorInfo) {
	 	 	 // Log the error here
	 	 	 console.error(error, errorInfo);
	 	} 		
	 	render() {
	 	 	 if (this.state.hasError) {
	 	 	 	 	return (
	 	 	 	 	 	 <div>
	 	 	 	 	 	 	 	<h2>Something went wrong</h2>
	 	 	 	 	 	 	 	<p>{this.state.errorMessage}</p>
	 	 	 	 	 	 </div>
	 	 	 	 	);
	 	 	 }
	 	 		
	 	 	 return this.props.children;
	 	}
}
class App extends Component {
	 	render() {
	 	 	 return (
	 	 	 	 	<div>
	 	 	 	 	 	 <h1>Error Handling with API Fetch</h1>
	 	 	 	 	 	 <ErrorBoundary>
	 	 	 	 	 	 	 	{/* error in a child component */}
	 	 	 	 	 	 	 	<ApiDataComponent />
	 	 	 	 	 	 </ErrorBoundary>
	 	 	 	 	</div>
	 	 	 );
	 	}
}
class ApiDataComponent extends Component {
	 	state = {
	 	 	 data: null,
	 	};
	 	
	 	componentDidMount() {
	 	 	 // Error by trying to fetch data from an invalid API endpoint
	 	 	 fetch('https://invalid-api-endpoint')
	 	 	 .then((response) => response.json())
	 	 	 .then((data) => this.setState({ data }))
	 	 	 .catch((error) => {
	 	 	 // Error and catch it in the ErrorBoundary
	 	 	 throw new Error('Error fetching data from the API');
	 	 	 });
	 	}
	 	
	 	render() {
	 	 	 return (
	 	 	 	 	<div className='App'>
	 	 	 	 	 	 <h3>API Data</h3>
	 	 	 	 	 	 {this.state.data ? (
	 	 	 	 	 	 	 	<ul>
	 	 	 	 	 	 	 	{this.state.data.map((item) => (
	 	 	 	 	 	 	 	 	 <li key={item.id}>{item.name}</li>
	 	 	 	 	 	 	 	))}
	 	 	 	 	 	 	 	</ul>
	 	 	 	 	 	 	 	) : (
	 	 	 	 	 	 	 	<p>Loading data...</p>
	 	 	 	 	 	 )}
	 	 	 	 	</div>
	 	 	 );
	 	}
}

export default App;

输出

使用 API fetch 进行错误处理

局限性

getDerivedStateFromError 应该是一个没有副作用的纯函数。如果我们必须执行诸如调用分析服务之类的活动,我们还应该使用 componentDidCatch。

在使用函数组件时,没有 getDerivedStateFromError 的直接等效项。为了提供类似的功能,我们可以构造一个 ErrorBoundary 组件或使用像 react-error-boundary 这样的包。

总结

了解 getDerivedStateFromError 对于正确管理 React 应用中的错误至关重要。如果将此方法合并到错误处理策略中,则可以通过显示有用的错误消息而不是令人困惑的 UI 问题来提供更好的用户体验。