课程章节: 第3章 神奇的 React 配合 typescript,完美输出
主讲老师:张轩
课程内容:
今天学习的内容包括:
3-21 Suspense 的概念
3-22 实践 Suspense
课程收获:
问:React Suspense有什么用呢?
答:在动态导入的帮助下,React Suspense让我们轻松定义延迟加载的组件。
两大用途:
动态加载组件
等待异步数据加载
const ProfilePage = React.lazy(() => import('./ProfilePage')); // Lazy-loaded
// Show a spinner while the profile is loading
<Suspense fallback={<Spinner />}>
<ProfilePage />
</Suspense>
Suspense 不是 “一个类似 axios 一样获取异步数据的库”, 而是 一种标准或者说是一种机制,当获取数据的库按照这种机制进行数据的操作的时候,它就可以享用 Suspense 的红利。
要完全支持 Suspense,就需要将现在的那些获取数据的第三方库,进行修改支持 Suspense 的特殊格式。
三种获取异步数据的解决方案
Fetch on render
const App = () => {
const [userDetails, setUserDetails] = useState({})
useEffect(() => {
fetchUserDetails().then(setUserDetails)
}, [])
if (!userDetails.id) return <p>Fetching user details...</p>
return (
<div className="app">
<h2>Simple Todo</h2>
<UserWelcome user={userDetails} />
<Todos />
</div>
)
}
Fetch-then-render
const fetchDataPromise = fetchUserDetailsAndTodos() // We start fetching here
const App = () => {
const [userDetails, setUserDetails] = useState({})
const [todos, setTodos] = useState([])
useEffect(() => {
fetchDataPromise.then((data) => {
setUserDetails(data.userDetails)
setTodos(data.todos)
})
}, [])
return (
<div className="app">
<h2>Simple Todo</h2>
<UserWelcome user={userDetails} />
<Todos todos={todos} />
</div>
)
}
Render-as-you-fetch
// 特别注意这个不是一个 Promise,而是一个需要特殊适配 Suspense 的类 Promise 的格式
const data = fetchData()
const App = () => (
<>
<Suspense fallback={<p>Fetching user details...</p>}>
<UserWelcome />
</Suspense>
<Suspense fallback={<p>Loading todos...</p>}>
<Todos />
</Suspense>
</>
)
const UserWelcome = () => {
const userDetails = data.userDetails.read()
// code to render welcome message
}
const Todos = () => {
const todos = data.todos.read()
// code to map and render todos
}
实践 Suspense
转换 Promise 为 Suspense 支持的数据结构。
wrapPromise 的工作机制:
接受 Promise 作为参数
当 Promise resolved,返回 resolved value
当 Promise rejected,throw 对应的 rejected value
当 Promise pending,throw 对应的 Promise 对象
暴露一个对应的 read 方法,来读取 Promise 的状态