ReactのError Boundaryでエラーをキャッチ!フォールバックUIでユーザーを安心させよう
React コンポーネントのレンダリングが中断され、フォールバック UI が指定されていないエラーについて
この問題を解決するには、以下の2つの方法があります。
フォールバック UI を指定する
Suspense コンポーネントを使用して、非同期処理が完了するまでの間、ユーザーに表示する代替 UI を指定することができます。Suspense コンポーネントの fallback
プロパティに、代替 UI として表示する React コンポーネントを指定します。
import React, { useState, Suspense } from 'react';
function MyComponent() {
const [data, setData] = useState([]);
// 非同期処理
useEffect(() => {
fetch('https://example.com/data.json')
.then((response) => response.json())
.then((json) => setData(json));
}, []);
if (!data.length) {
throw new Suspense({ fallback: <div>データ読み込み中...</div> });
}
return (
<div>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
}
function App() {
return (
<Suspense fallback={<div>読み込み中...</div>}>
<MyComponent />
</Suspense>
);
}
React.lazy を使用しない
React.lazy を使用して非同期にロードするコンポーネントを避けることもできます。React.lazy は、コンポーネントのレンダリングを遅らせるために使用されますが、Suspense コンポーネントと同様に、非同期処理が完了するまでコンポーネントのレンダリングが中断されます。
React.lazy を使用せずに、コンポーネントを直接インポートすることで、この問題を回避できます。
import React, { useState } from 'react';
function MyComponent() {
const [data, setData] = useState([]);
// 非同期処理
useEffect(() => {
fetch('https://example.com/data.json')
.then((response) => response.json())
.then((json) => setData(json));
}, []);
if (!data.length) {
return <div>データ読み込み中...</div>;
}
return (
<div>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
}
function App() {
return (
<MyComponent />
);
}
import React, { useState, Suspense } from 'react';
function MyComponent() {
const [data, setData] = useState([]);
// 非同期処理
useEffect(() => {
fetch('https://example.com/data.json')
.then((response) => response.json())
.then((json) => setData(json));
}, []);
if (!data.length) {
throw new Suspense({ fallback: <div>データ読み込み中...</div> });
}
return (
<div>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
}
function App() {
return (
<Suspense fallback={<div>読み込み中...</div>}>
<MyComponent />
</Suspense>
);
}
このコードでは、MyComponent
コンポーネント内で非同期処理が行われます。非同期処理が完了する前に render
メソッドが呼び出された場合、コンポーネントのレンダリングが中断され、エラーが発生します。
これを防ぐために、Suspense
コンポーネントを使用して、非同期処理が完了するまでの間、ユーザーに表示する代替 UI (フォールバック UI) を指定します。
import React, { useState } from 'react';
function MyComponent() {
const [data, setData] = useState([]);
// 非同期処理
useEffect(() => {
fetch('https://example.com/data.json')
.then((response) => response.json())
.then((json) => setData(json));
}, []);
if (!data.length) {
return <div>データ読み込み中...</div>;
}
return (
<div>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
}
function App() {
return (
<MyComponent />
);
}
import React, { useState, Suspense } from 'react';
function MyComponent() {
const [data, setData] = useState([]);
// 非同期処理
useEffect(() => {
fetch('https://example.com/data.json')
.then((response) => response.json())
.then((json) => setData(json));
}, []);
if (!data.length) {
throw new Suspense({ fallback: <div>データ読み込み中...</div> });
}
return (
<div>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
}
function App() {
return (
<Suspense fallback={<div>読み込み中...</div>}>
<MyComponent />
</Suspense>
);
}
import React, { useState } from 'react';
function MyComponent() {
const [data, setData] = useState([]);
// 非同期処理
useEffect(() => {
fetch('https://example.com/data.json')
.then((response) => response.json())
.then((json) => setData(json));
}, []);
if (!data.length) {
return <div>データ読み込み中...</div>;
}
return (
<div>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
}
function App() {
return (
<MyComponent />
);
}
Error Boundary を使用する
Error Boundary は、コンポーネント ツリー内で発生した JavaScript エラーをキャッチし、エラーを記録し、クラッシュしたコンポーネント ツリーの代わりにフォールバック UI を表示する React コンポーネントです。
Error Boundary を使用して、このエラーを処理することもできますが、Suspense とフォールバック UI を使用する方法の方が、より一般的で推奨される方法です。
import React, { useState } from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
}
componentDidCatch(error, info) {
console.error('Error:', error);
this.setState({ error });
}
render() {
if (this.state.error) {
return (
<div>
<h2>エラーが発生しました</h2>
<p>{this.state.error.message}</p>
</div>
);
}
return this.props.children;
}
}
function MyComponent() {
const [data, setData] = useState([]);
// 非同期処理
useEffect(() => {
fetch('https://example.com/data.json')
.then((response) => response.json())
.then((json) => setData(json));
}, []);
if (!data.length) {
throw new Error('データの読み込みに失敗しました');
}
return (
<div>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
}
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
reactjs