Next.js组件中Preact Signals导航状态异常问题求助
解决Next.js中Preact Signals控制移动端导航失效问题
问题背景
在Next.js项目的MobileNav组件中,使用@preact/signals替换原useState管理导航弹窗状态时出现以下问题:
- 仅在打开按钮的
isNavOpen.value = true;行报错,其他修改信号值的位置无报错 - 尝试类型断言或抽离状态修改函数后,报错消失,但导航完全失效,点击打开/关闭按钮均无反应
错误原因
- 信号状态读取错误:直接使用
!isNavOpen判断状态,而Preact Signal是一个包装对象,必须读取.value属性才能获取实际布尔值。直接判断对象会始终返回true(对象为真值),导致打开按钮永远不渲染,导航弹窗逻辑完全混乱。 - 不必要的类型断言破坏了信号的内部订阅机制,导致组件无法响应信号值的变化。
解决方案
- 所有判断信号状态的位置,必须通过
.value属性读取实际值 - 移除多余的类型断言,保留信号的原始定义
- 确保所有修改状态的逻辑正确设置
.value属性
修正后的完整代码
"use client"; import React from "react"; import { AnimatePresence, motion } from "framer-motion"; import { Route, routeCollection } from "../../data/route"; import { IonIcon } from "@ionic/react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { linkAppearAnimationVariant, linkContainerAnimationVariants, navScreenVariant, } from "../../animation/navbarVariants"; import { signal } from "@preact/signals"; const isNavOpen = signal<boolean>(false); const MobileNav = () => { const pathname = usePathname(); return ( <> {!isNavOpen.value && ( <div className="fixed right-12 top-12 md:hidden text-neutral-50" onClick={() => { isNavOpen.value = true; }} > Open </div> )} <AnimatePresence> {isNavOpen.value && ( <motion.div variants={navScreenVariant} initial="initial" animate="animate" exit="exit" className="w-full h-full flex flex-col justify-between absolute origin-top bg-main backdrop-blur-md md:hidden text-neutral-50 p-8" > <motion.div className="flex justify-between p-4 items-center"> <motion.p className="font-bold text-lg">Ayush</motion.p> <motion.p onClick={() => { isNavOpen.value = false; }} > Close </motion.p> </motion.div> <motion.div variants={linkContainerAnimationVariants} initial="initial" animate="animate" exit="initial" className="flex flex-col justify-between items-center gap-4" > {routeCollection.map((eachRoute, index) => ( <div className="overflow-hidden" key={index}> <LinkRender eachRoute={eachRoute} pathName={pathname} closeTab={() => { isNavOpen.value = false; }} /> </div> ))} </motion.div> <motion.a href="mailto:ayushmondal001@gmail.com" className="underline underline-offset-2 text-center" > Contact Me </motion.a> </motion.div> )} </AnimatePresence> </> ); }; const LinkRender = ({ eachRoute, pathName, closeTab, }: { eachRoute: Route; pathName: string; closeTab: () => void; }) => { return ( <motion.div variants={linkAppearAnimationVariant} onClick={closeTab}> <Link href={eachRoute.address}> <motion.div className={`flex gap-2 items-center font-bold text-md ${ pathName === eachRoute.address ? "text-extraLight" : "" }`} > <IonIcon icon={eachRoute.iconText}></IonIcon> <span>{eachRoute.name}</span> </motion.div> </Link> </motion.div> ); }; export default MobileNav;
关键修改点
- 将
{!isNavOpen && ...}改为{!isNavOpen.value && ...} - 将
{isNavOpen && ...}改为{isNavOpen.value && ...} - 移除了类型断言,恢复信号的原始定义
const isNavOpen = signal<boolean>(false);
内容的提问来源于stack exchange,提问作者AYUSH Mondal
相关产品推荐
相关产品推荐

