Next.js中useSWR+getServerSideProps+GraphQL在JS禁用时渲染异常
问题分析与解决方案
问题描述
使用Next.js的pages/api功能搭配graphql-yoga搭建GraphQL接口(地址:http://localhost:3000/api/graphql),通过mongoose获取数据。目标是结合getServerSideProps()与useSWR实现SSR页面,当前功能已实现,但在Chrome禁用JavaScript并刷新页面后,数据与CSS无法正常渲染。
问题原因
- SWR缓存Key不匹配:
getServerSideProps中返回的fallback使用graphqlUrl作为缓存Key,但useSWR的缓存Key是booksQuery,两者不匹配。禁用JS时,SWR无法找到对应的fallback数据,导致组件停留在“Loading...”状态,无法渲染数据。 - CSS依赖JavaScript加载:若使用的CSS方案需要JS动态注入(如部分CSS-in-JS库、动态添加的style标签),禁用JS后CSS无法被正确加载到页面中,导致样式失效。
解决方案
1. 修正SWR Fallback的缓存Key
确保getServerSideProps中fallback的Key与useSWR的缓存Key完全一致,将Key从graphqlUrl改为booksQuery:
修改pages/index.js中的getServerSideProps:
export async function getServerSideProps() { const repoInfo = await fetcher(booksQuery); return { props: { fallback: { // 与useSWR的第一个参数(缓存Key)保持一致 [booksQuery]: repoInfo } } }; }
2. 确保CSS在无JS环境下生效
- 使用Next.js内置CSS支持:直接导入
.css文件或CSS模块,Next.js会将CSS打包为静态资源并在HTML中直接引入,无需JS即可生效。可在pages/_app.js中全局导入全局CSS,或在组件内导入CSS模块。 - 配置CSS-in-JS的SSR支持:若使用styled-components等CSS-in-JS库,需安装
babel-plugin-styled-components并在项目配置中启用,确保服务端渲染时CSS能被正确注入到HTML中。 - 避免动态CSS:不要通过
useEffect等JS逻辑动态添加style标签,改用静态CSS或支持SSR的样式方案。
3. 优化无JS环境下的组件渲染逻辑
直接将getServerSideProps获取的初始数据传递给组件,即使SWR因禁用JS无法工作,也能直接渲染数据:
修改pages/index.js的组件部分:
export async function getServerSideProps() { const repoInfo = await fetcher(booksQuery); return { props: { initialData: repoInfo, fallback: { [booksQuery]: repoInfo } } }; } function Repo({ initialData }) { // 使用initialData作为兜底数据 const { data = initialData, error } = useSWR(booksQuery, fetcher, { initialData }); if (error) return "An error has occurred."; // 有初始数据时直接跳过加载状态 if (!data) return "Loading..."; const { books } = data return <Home data={books} /> } export default function Index({ initialData, fallback }) { return ( <SWRConfig value={{ fallback }}> <Repo initialData={initialData} /> </SWRConfig> ) }
内容的提问来源于stack exchange,提问作者Billy
相关产品推荐
相关产品推荐

