Next.js预取数据报错:TypeError: Cannot read properties of null (reading 'useState')
问题分析与修复方案
问题背景
你在Next.js项目中尝试通过自定义工具函数在getStaticProps和getStaticPaths中预取API数据时,遇到了错误:TypeError: Cannot read properties of null (reading 'useState')。相关代码如下:
1. 后端API代码
// api/projectsdata.js export default function handler(req, res) { res.status(200).json([{...},{...},{...}]); }
2. 带React Hooks的数据获取工具
import { useEffect, useState } from "react"; const ProjectsUtil = () => { const [data, setData] = useState(null); const fetchData = async () => { try { const response = await fetch("http://localhost:3000/api/projectsdata"); const data = await response.json(); if (response.ok) { setData(data); } } catch (error) { throw new Error(error); } }; useEffect(() => { fetchData(); }, []); return data !== null && data; }; export default ProjectsUtil;
3. 数据获取辅助函数
export const getAllProjects = () => { const data = ProjectsUtil(); return data; }; export const getProjectByName = (name) => { const data = getAllProjects(); return data.filter((project) => project.name === name); };
4. 组件中的预取逻辑
const SingleProjectDetails = (props) => { return <ProjectDetails props={props.projectData[0]} />; }; export function getStaticProps(context) { const { params } = context; const { id } = params; const projectData = getProjectByName(id); return { props: { projectData: projectData, }, revalidate: 600, }; } export function getStaticPaths() { const projectsData = getAllProjects(); return { paths: projectsData.map((project) => ({ params: { id: project.name, }, })), fallback: true, }; }
错误原因
- React Hooks使用规则被打破:
ProjectsUtil是自定义Hook(调用了useState和useEffect),自定义Hook只能在React组件顶层或其他自定义Hook中调用,不能像普通函数一样在getStaticProps/getStaticPaths这类非React渲染流程中直接执行。 getStaticProps/getStaticPaths的执行环境:这两个函数在构建阶段或服务器端同步执行,不属于React组件渲染周期,完全不支持React Hooks,直接调用会抛出错误。- 之前在其他组件中能正常运行,是因为你在组件顶层调用该自定义Hook,符合Hooks使用规则。
修复方案
把数据获取逻辑改成纯异步工具函数,去掉React Hooks,直接在getStaticProps/getStaticPaths中异步调用:
1. 重构数据获取工具(去掉Hooks)
// 纯异步工具函数,不依赖React Hooks export const fetchAllProjects = async () => { try { const response = await fetch("http://localhost:3000/api/projectsdata"); if (!response.ok) { throw new Error(`请求失败,状态码:${response.status}`); } return await response.json(); } catch (error) { console.error("获取项目数据出错:", error); throw error; } };
2. 重构辅助函数为异步函数
export const getAllProjects = async () => { return await fetchAllProjects(); }; export const getProjectByName = async (name) => { const allProjects = await getAllProjects(); return allProjects.filter(project => project.name === name); };
3. 修改getStaticProps/getStaticPaths为异步函数
const SingleProjectDetails = (props) => { return <ProjectDetails props={props.projectData[0]} />; }; // 改为async函数 export async function getStaticProps(context) { const { params } = context; const { id } = params; const projectData = await getProjectByName(id); return { props: { projectData, }, revalidate: 600, }; } // 改为async函数 export async function getStaticPaths() { const projectsData = await getAllProjects(); return { paths: projectsData.map(project => ({ params: { id: project.name }, })), fallback: true, }; }
补充说明
Next.js完全允许在getStaticProps/getStaticPaths中预取API数据,核心是要遵循这两个函数的执行规则:
- 支持异步逻辑(用
async/await) - 不能依赖React Hooks或浏览器端API
- 执行环境是服务器端/构建阶段,而非浏览器客户端
内容的提问来源于stack exchange,提问作者Roma Kim
相关产品推荐
相关产品推荐

