当涉及到手写 React 的 Suspense 和 lazy 功能时,你通常需要理解这两个概念是如何协同工作的。Suspense 是一种用于处理异步加载的组件的加载状态的机制,而 lazy 则是一种使组件能够被按需加载的工具。
下面是一个简单的示例,展示如何手动实现类似于 Suspense 和 lazy 的功能:
// 自定义的实现 Suspense 组件
class CustomSuspense extends React.Component {
constructor(props) {
super(props);
this.state = {
isPending: true, // 是否处于等待状态
error: null, // 异步加载时的错误
};
}
componentDidMount() {
// 当组件加载完成后,开始执行异步加载操作
this.props.promise
.then(() => {
// 异步加载成功,设置 isPending 为 false
this.setState({ isPending: false });
})
.catch(error => {
// 捕获异步加载的错误,设置 isPending 为 false,并存储错误信息
this.setState({ isPending: false, error });
});
}
render() {
if (this.state.isPending) {
// 如果正在等待加载完成
if (this.props.fallback) {
// 如果传递了自定义的 fallback 组件,则显示它
return this.props.fallback;
}
return "Loading..."; // 默认加载提示
} else if (this.state.error) {
// 如果加载过程中出现了错误
return `Error: ${this.state.error.message}`; // 显示错误消息
} else {
// 如果加载成功并且没有错误,渲染子组件
return this.props.children; // 加载完成后渲染子组件
}
}
}
// 自定义的实现 lazy 函数
function customLazy(importFunction) {
let component;
let error;
const promise = importFunction()
.then(module => {
component = module.default || module; // 获取导入的组件
})
.catch(err => {
error = err; // 捕获导入错误
});
return props => {
if (error) {
throw error; // 抛出导入错误
}
if (!component) {
throw promise; // 抛出未加载完成的 promise
}
return React.createElement(component, props); // 创建组件
};
}
// 使用示例
const LazyComponent = customLazy(() => import("./LazyComponent"));
function App() {
return (
<div>
<h1>Hello Suspense and Lazy</h1>
<CustomSuspense promise={LazyComponent}>
<LazyComponent />
</CustomSuspense>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
在这个示例中,手动实现了一个简化版的 CustomSuspense 和 customLazy,以展示它们的基本工作原理。实际的 React 实现更加复杂且健壮,但这个例子可以帮助你理解这些概念的核心思想。在现实应用中,你通常会使用 React 的内置 Suspense 和 lazy 来处理异步加载和懒加载组件。
上面的示例是使用类组件实现的。以下是相同功能的代码,但使用函数组件和 React Hooks 进行实现:
import React, { useState, useEffect } from 'react';
// 自定义的实现 Suspense 组件
function CustomSuspense({ promise, fallback, children }) {
const [isPending, setIsPending] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
promise
.then(() => {
setIsPending(false);
})
.catch(err => {
setIsPending(false);
setError(err);
});
}, [promise]);
if (isPending) {
if (fallback) {
return fallback;
}
return "Loading..."; // 默认加载提示
} else if (error) {
return `Error: ${error.message}`; // 显示错误消息
} else {
return children; // 加载完成后渲染子组件
}
}
// 自定义的实现 lazy 函数
function customLazy(importFunction) {
let component;
let error;
const promise = importFunction()
.then(module => {
component = module.default || module; // 获取导入的组件
})
.catch(err => {
error = err; // 捕获导入错误
});
return props => {
if (error) {
throw error; // 抛出导入错误
}
if (!component) {
throw promise; // 抛出未加载完成的 promise
}
return React.createElement(component, props); // 创建组件
};
}
// 使用示例
const LazyComponent = customLazy(() => import("./LazyComponent"));
function App() {
return (
<div>
<h1>Hello Suspense and Lazy</h1>
<CustomSuspense promise={LazyComponent}>
<LazyComponent />
</CustomSuspense>
</div>
);
}
export default App;
这个版本的代码使用了函数组件和 useState、useEffect 等 React Hooks 来实现相同的功能。函数组件加上 Hooks 是一种更现代、更简洁的写法,能够更好地处理组件的状态和副作用。希望这个函数组件版本的示例对你有所帮助!