Wrapper交互组件
本质是Server Component 包裹 Client Component,很多时候我们可能在某个图片、某个div块上有交互事件,我们不希望整个块都变为client组件,那么我们就可以进行一个wrapper包裹
Image组件
Image组件有两种使用模式,一种是fill 模式,一种是固定尺寸的w\h模式,但是个人认为前者其实更适合大部分项目,后者限制比较大,毕竟我们要做自适应,设计给的单位又是px,fill模式是对Image对二次封装,通过relative+tailwindcss对classname实现
用法,很直观明了了
<InternalImage alt='coin' src='/game-king/icon-coin.png' className='w-[18px] h-[18px]' />
fetch+React Query结合
这里的场景是我想要保持在server端fetch数据,比如我拉取了一个为10的总数,现在我点击按钮要提交数据-1,提交之后乐观更新总数为9,从server端转client端去fetch total数据
server组件,fetch数据,将res传给client组件
client交互组件,将传入的res作为initialData传给useQuery,返回的data我们就可以做一些操作,通过mutaion去做一些乐观更新,第一次进来这里的useQuery并不会调用接口(提供了数据命中staleTime缓存),在network是看不到,不用担心重复调用
React Query的HydrationBoundary预拉取数据
Image custom Loader
我单独写了一篇文章 Next项目中静态资源的压缩、优化
template.tsx、loading.tsx
template.tsx在我业务中主要可以提供一个比较好的路由跳转的转场动画,本身路由跳转其实很生硬,会让用户意外卡了,感受比较差。除此之外,我们也要利用好Link标签和prefetch路由
组件本质就是写一个动画,我这里用了framer-motion库,本身项目使用这个也比较多
loading.tsx主要是在我们在page异步fetch的时候提供一个loading效果,当然这个效果出现的概率很少,大部分页面加载很快,一旦路由段加载完成(即页面组件渲染完毕),会自动被替换为实际页面内容,它是一个特殊的边界组件,是由 Next.js 自动管理的。
这里做了一个假的进度条的效果
RouterWrapper
这个也是Wrapper的一种,主要是针对我们用router来跳转,对各种跳转场景做了一个封装,基本覆盖了所有场景。
prefetch可以提前帮我们拉取下一个页面的rsc,跳转更快,但是最好可以做一个IntersectionObserver的判断,如果全部挂上prefetch,在pm2日志所有路由都进行请求,个人感觉这是种浪费
fetch客户端/服务端
cahce、Promise.all
cache可以让我们同一个接口在页面中多次使用,只fetch一次,类似reactQuery的命中缓存的效果
Promise.all并行请求,多个await是串行队列,比较间隔多一个空白区
dynamic
nextjs有两个dynamic,一个是针对page页面,一个是组件级别的
export const dynamic在 Next.js App Router 中,export const dynamic 是一个页面级或布局级的配置选项,用于控制rendering mode。它影响页面是静态生成force-static还是动态渲染force-dynamic,如果你开发的是官方这类的可以用force-static,大部分情况都是force-dynamic
然后你也可以在build是时候看的哪个路由是静态or动态
'force-dynamic':
- 页面依赖用户特定数据(如登录状态、个性化内容)。
- 需要每次请求时获取最新数据(例如实时 API 数据、数据库查询)。
- 页面使用动态函数如
cookies()、headers()、searchParams(如果需要服务器端处理)。 - 禁用缓存或预渲染(例如用于确保排行榜数据实时更新)。
组件级别dynamic它是 next/dynamic 函数,用于动态导入(dynamic import)组件,实现代码分割(code splitting)和懒加载(lazy loading)。
- 性能优化:当组件很大或不立即需要时,使用动态导入可以将代码分割成单独的 chunk,只在需要时加载。减少初始 bundle 大小,提升首屏加载速度。
- 条件渲染:组件只在特定条件下显示(例如用户交互后Dialog)。
- 避免 SSR:如果组件依赖浏览器 API(如 window),用
ssr: false确保只在客户端渲染。(自家的AppBrigde)
cahce()、useCache、fetch的cache、revalidate和tag、浏览器的cache-control
Suspence、LazyLoadWrapper(IntersectionObserver)
API route.ts
tailwindcss w-10=>w-[10px] vscode插件开发
项目做了移动端的自适应px转vw,设计提供的单位也是px,所以项目基本是以px为开发基调,那么就会存在一个问题,tailwindcss需要对px进行包裹+px单位的书写,这在实际的开发中其实很浪费时间,每次都要去加[]px,为了解决这个问题,开发了一个vscode插件
当我们写w-10,在通过Ctrl+S保存,会自动转化为w-[10px]
插件本身的开发并不难,至少在这个插件上hh,本质通过正则去匹配然后转换
Typescript常用
Omit: Omit<CountdownProps, 'targetDate'>
Pick: Pick<CountdownProps, 'className' | 'textClassName' | 'wrapperClassName'>
extends: type ToArray<T> = T extends any ? T[] : never
泛型: 传T返T
export async function safeFetch<T>(fetcher: () => Promise<T>): Promise<T | null> {
if (!isServer) {
throw new Error("safeFetch should only be called on server")
}
try {
return await fetcher()
} catch (error) {
console.error("[Server] API failed:", error)
return null
}
}
ComponentProps: ComponentProps<typeof Image>
函数重载:入参的类型、参数的个数,返回值不同
function parse(input: string): object
function parse(input: string, strict: true): object
function parse(input: string, strict: false): string
function parse(input: string, strict?: boolean) {
if (strict === false) return input
return JSON.parse(input)
}
const a = parse("{}", true) // object
const b = parse("{}", false) // string