Next.js 13组件在useEffect触发前提前渲染问题解决
解决Next.js组件提前渲染问题,等待用户规则校验完成
问题核心是existingUser初始值为false,导致校验过程中直接渲染表单。要解决这个问题,需要新增状态跟踪校验是否完成,在校验期间显示加载组件,直到校验结束再决定渲染表单或跳转。
修改步骤:
新增校验状态
添加isCheckingUser状态,初始值设为true,用来标记是否正在校验用户的规则同意状态:const [existingUser, setExistingUser] = useState(false); const [isCheckingUser, setIsCheckingUser] = useState(true); // 新增状态 const [isChecked, setIsChecked] = useState([false, false, false, false, false]);更新校验函数
修改checkExistingUser函数,在Firestore请求完成后结束校验状态,同时处理文档不存在的异常情况:const checkExistingUser = async () => { try { const docRef = doc(db, "users", user); const docSnap = await getDoc(docRef); // 先判断文档是否存在,再检查rulesAccepted字段 if (docSnap.exists() && docSnap.data().rulesAccepted === true) { setExistingUser(true); } else { setExistingUser(false); } } catch (error) { console.error("校验用户状态失败:", error); setExistingUser(false); // 出错时默认设为未同意规则 } finally { setIsCheckingUser(false); // 无论成功失败,都结束校验状态 } };添加校验中加载判断
在原有的loading判断后,新增isCheckingUser的判断,在校验过程中始终显示加载组件:if (loading || isCheckingUser) { // 合并Auth加载和用户校验加载状态 return <LoadingCircle />; }
关键修改后的组件片段:
function Rules() { const { data: session } = useSession(); const router = useRouter(); const { user, loading } = useAuth(); const [existingUser, setExistingUser] = useState(false); const [isCheckingUser, setIsCheckingUser] = useState(true); const [isChecked, setIsChecked] = useState([false, false, false, false, false]); const checkExistingUser = async () => { try { const docRef = doc(db, "users", user); const docSnap = await getDoc(docRef); if (docSnap.exists() && docSnap.data().rulesAccepted === true) { setExistingUser(true); } else { setExistingUser(false); } } catch (err) { console.error("获取用户数据失败:", err); setExistingUser(false); } finally { setIsCheckingUser(false); } }; useEffect(() => { if (user) { checkExistingUser(); } else { setIsCheckingUser(false); // 无用户时直接结束校验 } }, [user]); // ... 其他逻辑保持不变 if (loading || isCheckingUser) { return <LoadingCircle />; } // ... 原表单渲染部分不变 }
为什么之前的if(!existingUser)不生效?
因为existingUser初始值是false,在校验请求完成前它不会被更新,所以!existingUser始终为true,会直接渲染表单。新增isCheckingUser状态后,我们可以明确区分「正在校验」和「校验完成且未同意规则」两种状态,避免提前渲染表单。
内容的提问来源于stack exchange,提问作者Walid Daniel Dib
相关产品推荐
相关产品推荐

