Next.js中函数组件结合Hooks使用axios请求数据报404如何解决
问题报错
开发Next.js函数组件过程中,使用axios发起数据请求时控制台抛出错误:AxiosError: Request failed with status code 404
问题复现代码如下:
import { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; import axios from "axios"; const Post = () => { let params = useParams(); const [post, setPost] = useState(null) useEffect(() => { axios.get('https://jsonplaceholder.typicode.com/posts') .then(post => { setPost(post) }); }, []) return ( <div> {post !== null ? ( <div> <h4>{res.data.title}</h4> <p>{res.data.body}</p> </div> ) : ( <div>Loading post...</div> )} </div> ) } export default Post
问题原因
代码存在4个核心问题,共同触发报错和渲染异常:
- 技术栈适配错误:Next.js 自带文件系统路由能力,无需额外引入
react-router-dom。该库的useParamsHook无法解析Next.js的路由参数,若原本逻辑是要将动态帖子id拼接到请求路径,参数解析为undefined时会生成无效请求地址,直接触发404错误。 - 接口与业务逻辑不匹配:当前写死的
/posts地址是获取全量帖子列表的接口,若组件为单篇帖子详情页,未携带帖子id请求单条数据接口,实际运行时如果路径拼接错误(比如多打斜杠、漏写路径段)就会返回404。 - 变量引用错误:axios请求的then回调中将响应对象命名为
post,但JSX渲染时引用了未定义的res变量,就算请求成功也会抛出引用错误,无法正常渲染内容。 - 缺少异常捕获:请求逻辑没有catch分支处理错误,接口异常时会直接抛出未捕获的Promise错误。
修正方案
- 替换路由依赖:删除
react-router-dom相关引入,根据你使用的Next.js路由模式引入官方Hook获取参数:- Next.js 13+ App Router:从
next/navigation引入useParams - Next.js 旧版本Pages Router:从
next/router引入useRouter获取路由参数
- Next.js 13+ App Router:从
- 修正请求逻辑:根据业务需求选择请求单条/全量接口,将解析到的路由参数正确拼接到请求路径,把路由参数加入useEffect依赖数组,参数变化时自动重新拉取数据。
- 统一变量命名:对齐回调参数和渲染时的变量引用,注意axios响应的真实业务数据存放在响应对象的
data字段中。 - 增加错误兜底:添加请求异常捕获逻辑,增加错误状态的页面提示。
单篇帖子详情页修正代码(App Router示例)
// 注意:使用客户端组件需要在文件顶部添加'use client'声明 'use client' import { useState, useEffect } from "react"; // 替换react-router-dom的useParams为Next.js官方Hook import { useParams } from "next/navigation"; import axios from "axios"; const Post = () => { const params = useParams(); const [post, setPost] = useState(null); const [error, setError] = useState(null); useEffect(() => { // 拼接动态帖子id,请求单条帖子接口 axios.get(`https://jsonplaceholder.typicode.com/posts/${params.id}`) .then(res => { // 存储接口返回的真实数据 setPost(res.data); }) .catch(err => { setError(err); }); }, [params.id]) // 错误状态兜底 if (error) return <div>帖子加载失败,请稍后重试</div> return ( <div> {post !== null ? ( <div> <h4>{post.title}</h4> <p>{post.body}</p> </div> ) : ( <div>Loading post...</div> )} </div> ) } export default Post
全量帖子列表页适配提示
如果你的需求是拉取全量帖子列表,不需要动态路由参数,直接修正变量引用、遍历数组渲染即可,核心逻辑调整如下:
useEffect(() => { axios.get('https://jsonplaceholder.typicode.com/posts') .then(res => { // 此时res.data为帖子数组 setPost(res.data); }) .catch(err => setError(err)); }, []) // 渲染部分遍历数组 {post !== null ? ( <div> {post.map(item => ( <div key={item.id}> <h4>{item.title}</h4> <p>{item.body}</p> </div> ))} </div> ) : ( <div>Loading post list...</div> )}
内容的提问来源于stack exchange,提问作者amit
相关产品推荐
相关产品推荐

