React 预加载

cache – React 中文文档

React 中实现预加载模式可以使用 cache API,它会缓存一个函数返回的结果

const getUser = cache(async (id) => {  
	return await db.user.query(id);  
}  
 
async function Profile({id}) {  
	const user = await getUser(id);  
	return (  
		<section>  
			<img src={user.profilePic} />  
			<h2>{user.name}</h2>  
		</section>  
	);  
}  
 
function Page({id}) {  
	// ✅ 正确示例:开始获取用户数据。  
	getUser(id);  
	// ……一些计算工作  
	return (  
		<>  
			<Profile id={id} />  
		</>  
	);  
}

在渲染 Page 时,组件调用 getUser,但是它并没有使用返回的数据,只是发起数据请求,这个早期的 getUser 调用会启动异步数据查询,而在 Page 执行其他计算工作并渲染子组件时进行。

在渲染 Profile 时,我们再次调用 getUser, 如果初始 getUser 调用已经返回并缓存了用户数据,那么当 Profle请求并等待这些数据 时,它可以简单的从缓存中获取,而无需进行另一个远程过程调用。如果初始 fetchData 还没有完成,那么在这种模式下预加载数据可以减数据获取的延迟。

NextJs 预加载

使用预加载数据的方式可以避免出现串行请求

串行请求与并行请求

image.png

预加载数据在NextJS的实现方式可以单独从组件内导出一个数据获取函数,这个数据函数可以预先在组件加载之前就开始获取数据,这样等组件加载完成之后数据也就获取了

场景:

通过一个异步请求来控制合适加载某个组件,例如需要获取到用户信息之后,再渲染某个模块,而这个模块又跟用户信息没有关系,如果不使用预加载数据的话,流程需要先获取用户信息,然后渲染模块,模块内的数据请求才会发起

使用预加载数据的话,可以在模块加载之前就获取到数据,并且不需要通过 props 向下传递数据

定义并导出组件和数据获取函数

// components/Item.js
import { getItem } from '@/utils/get-item'
 
export const preload = (id) => {
	void getItem(id)
}
 
export default async function Item({ id }) {
  const result = await getItem(id)
  // ...
}

预加载数据

// app/item/[id]/page.js
import Item, { preload, checkIsAvailable } from '@/components/Item'
 
export default async function Page({ params: { id } }) {
  // 开始加载 item 数据
  preload(id)
  // 执行另一个异步任务
  const isAvailable = await checkIsAvailable()
 
  return isAvailable ? <Item id={id} /> : null
}

NextJs 中 fetch 会默认缓存数据

预加载模式与React catch 和 server-only 一起使用

NextJS 中,可以创建一个工具函数,将 React catch 和 server-only 以及 预加载模式一起使用,来优化数据获取

// utils/get-item.js
import { cache } from 'react'
import 'server-only'
 
export const preload = (id) => {
  void getItem(id)
}
 
export const getItem = cache(async (id) => {
  // ...
})

使用这种方式,可以快速获取数据、缓存返回结果并保证数据获取只发生在服务端。布局、页面或者其他组件可以使用 utils/get-items

掘金小册