NextJS 14 SSR:初始渲染后如何在客户端添加列表项
Next.js 14 客户端列表加载更多优化方案
你当前的实现能跑,但确实有冗余逻辑可以简化,同时完全保留服务器初始渲染的SEO和加载速度优势。下面是更简洁的最佳实践方案:
核心优化点
- 直接用服务器传递的初始
jobs初始化客户端状态,省去额外的useEffect同步步骤 - 使用函数式更新更新列表状态,避免因闭包导致的旧状态问题
- 移除冗余的
initialRender和didMount判断,统一渲染逻辑 - 可选添加加载状态,提升用户体验
优化后的代码
服务器组件(无需改动)
const jobResults = await getPagedJobsData(query) return ( <HomePage data={jobResults}/> )
客户端组件(优化版)
'use client' import { useState } from 'react' const Home = ({ data }) => { const { jobs: initialJobs } = data // 直接用服务器传递的初始数据初始化客户端状态 const [jobData, setJobData] = useState(initialJobs) const [currentPage, setCurrentPage] = useState(1) const [isLoading, setIsLoading] = useState(false) const loadMoreJobs = async () => { setIsLoading(true) try { const query = { page_num: currentPage + 1, title: '', location: '', contractTypeSel: '', remoteDays: "Any", skills: '' } const newResults = await getPagedJobsData(query) // 函数式更新,确保拿到最新的jobData状态 setJobData(prev => [...prev, ...newResults.jobs]) setCurrentPage(prev => prev + 1) } catch (err) { // 可选:添加错误处理 console.error('加载更多失败:', err) } finally { setIsLoading(false) } } return ( <> <div className='border'> <div> <div> {/* 统一渲染逻辑,不再区分初始渲染和客户端更新 */} {jobData.map((item, index) => ( <div key={index}>{item.company}</div> ))} </div> </div> </div> <div className='items-center'> <button onClick={loadMoreJobs} disabled={isLoading} > {isLoading ? '加载中...' : '加载更多'} </button> </div> </> ) } export default Home
优化说明
- 状态初始化:直接将服务器传递的
initialJobs作为useState的初始值,这样客户端首次渲染就用服务器数据,完全保留SEO优势,同时省去了同步状态的useEffect。 - 函数式更新:
setJobData(prev => [...prev, ...newResults.jobs])这种写法能确保我们基于最新的状态更新,避免闭包导致的旧状态覆盖问题,比直接用[...jobData, ...addtionalJobs]更可靠。 - 移除冗余逻辑:不需要再用
initialRender区分渲染源,因为jobData初始值就是服务器数据,后续更新后直接渲染最新数组即可。 - 加载状态:添加
isLoading状态防止重复点击,同时给用户明确的加载反馈,提升体验。
内容的提问来源于stack exchange,提问作者nobby nob
相关产品推荐
相关产品推荐

