Next.js中useEffect内setState未触发问题排查
为什么调用setCurrent后current仍显示初始值?
问题场景
在Next.js客户端组件中,useEffect里的所有console.log都能输出正确的路由值,但调用setCurrent(router.asPath)后,紧接着打印current却还是初始值TEST。
代码示例
import { useContext, useEffect, useState } from "react"; import Link from "next/link"; import { UserContext } from "../context"; import { useRouter } from "next/router"; const Nav = () => { const [current, setCurrent] = useState("TEST"); const [state, setState] = useContext(UserContext); const router = useRouter(); // 先判断是否运行在客户端,是则将状态设置为路径名,路径变化时更新 useEffect(() => { console.log("router.asPath ", router.asPath); console.log("window.location.pathname is ", window.location.pathname); console.log(typeof window !== "undefined"); if (typeof window !== "undefined") { console.log("this ran before"); setCurrent(router.asPath); console.log("this ran after"); console.log("current is ", current); } }, [typeof window !== "undefined" && window.location.pathname]); //... }
控制台输出
router.asPath /register window.location.pathname is /register true this ran before this ran after current is TEST
原因分析
React状态更新是异步的
setCurrent是异步操作,调用后不会立刻修改current的值。你在调用setCurrent后马上打印的current,是当前函数闭包里捕获的旧状态值,不是更新后的新值。useEffect依赖数组存在逻辑问题
你写的依赖项[typeof window !== "undefined" && window.location.pathname]有问题:
- 这个表达式会返回布尔值或路径字符串,依赖关系不稳定,可能导致useEffect触发异常
- 在Next.js中,直接依赖
router.asPath监听路由变化更可靠,useRouter本身就是客户端钩子,无需手动判断window
解决方法
调整useEffect的依赖,并通过监听current的变化验证状态更新:
import { useContext, useEffect, useState } from "react"; import Link from "next/link"; import { UserContext } from "../context"; import { useRouter } from "next/router"; const Nav = () => { const [current, setCurrent] = useState("TEST"); const [state, setState] = useContext(UserContext); const router = useRouter(); useEffect(() => { console.log("router.asPath ", router.asPath); // 直接更新状态 setCurrent(router.asPath); }, [router.asPath]); // 依赖router.asPath,路由变化时自动触发 // 专门监听current的变化,打印更新后的值 useEffect(() => { console.log("current已更新为: ", current); }, [current]); //... }
修改后,路由变化时current会被正确更新,第二个useEffect会在current变化时打印出新值。
内容的提问来源于stack exchange,提问作者Corey Stewart
相关产品推荐
相关产品推荐

