Astro中React组件无法运行,无法访问环境变量求助
问题现象
- 移动端菜单按钮点击无响应
- 页面加载时抛出错误:
[Error] [astro-island] Error hydrating /src/components/Navbar.tsx Error: Missing Supabase URL or anon key Module Code — supabase.ts:7 (anonymous function) (localhost:1171:3738)
Navbar组件代码
import { useState, useEffect } from "react"; import { Menu, X, User, LogOut } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { supabase } from "@/lib/supabase"; export const Navbar = () => { const [open, setOpen] = useState(false); const [loggedIn, setLoggedIn] = useState(false); const checkUser = async () => { const session = await supabase.auth.getSession(); if (session) { setLoggedIn(true); } else { setLoggedIn(false); } }; checkUser(); return ( <nav className="bg-white border-b sticky top-0"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="relative flex items-center justify-between h-16"> <div className="flex-1 flex items-center justify-start sm:items-stretch sm:justify-start"> <div className="flex-shrink-0"> <a href="/"> <img className="h-8 w-auto" src="/favicon.svg" alt="Workflow" /> </a> </div> <div className="hidden sm:block sm:ml-6"> <div className="flex space-x-2"> <a href="#" className="text-gray-900 hover:text-gray-500 hover:text-white px-3 py-2 text-sm" > Stories </a> <a href="#" className="text-gray-900 hover:text-gray-500 hover:text-white px-3 py-2 text-sm" > Writers </a> <a href="#" className="text-gray-900 hover:text-gray-500 hover:text-white px-3 py-2 text-sm" > Blog </a> <a href="#" className="text-gray-900 hover:text-gray-500 hover:text-white px-3 py-2 text-sm" > About </a> </div> </div> </div> <div className="flex items-center space-x-2"> {!loggedIn && ( <> <Button className="hidden sm:inline-block" variant="outline"> Login </Button> <Button className="hidden sm:inline-block">Sign Up</Button> </> )} {loggedIn && ( <DropdownMenu> <DropdownMenuTrigger> <Avatar className="h-8 w-8"> <AvatarImage src="https://github.com/shadcn.png" /> <AvatarFallback>CN</AvatarFallback> </Avatar> </DropdownMenuTrigger> <DropdownMenuContent> <a href="/profile"> <DropdownMenuItem> <User /> My Profile </DropdownMenuItem> </a> <DropdownMenuItem> <LogOut /> Log out </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> )} <div className="sm:hidden"> <button type="button" className="inline-flex items-center justify-center text-gray-500 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white" aria-controls="mobile-menu" aria-expanded={open ? "true" : "false"} onClick={() => setOpen(!open)} > <span className="sr-only">Open main menu</span> {open ? ( <X className="block h-6 w-6" aria-hidden="true" /> ) : ( <Menu className="block h-6 w-6" aria-hidden="true" /> )} </button> </div> </div> </div> </div> <div className={`sm:hidden ${open ? "block" : "hidden"}`} id="mobile-menu" > <div className="px-2 pt-2 pb-3 space-y-1"> <a href="#" className="text-gray-900 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium" > Dashboard </a> <a href="#" className="text-gray-900 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium" > Team </a> <a href="#" className="text-gray-900 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium" > Projects </a> <a href="#" className="text-gray-900 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium" > Calendar </a> <div className="mt-4 space-y-1"> <Button className="w-full" variant="outline"> Login </Button> <Button className="w-full">Sign Up</Button> </div> </div> </div> </nav> ); };
Supabase配置文件(@/lib/supabase.ts)
import { createClient } from "@supabase/supabase-js"; const supabaseUrl = import.meta.env.SUPABASE_URL; const supabaseAnonKey = import.meta.env.SUPABASE_ANON_KEY; if (!supabaseUrl || !supabaseAnonKey) { throw new Error("Missing Supabase URL or anon key"); } export const supabase = createClient(supabaseUrl, supabaseAnonKey);
解决建议
1. 修复Supabase环境变量读取问题
- Astro中客户端组件无法读取不带
PUBLIC_前缀的环境变量,需修改.env文件中的变量名:PUBLIC_SUPABASE_URL=你的Supabase地址 PUBLIC_SUPABASE_ANON_KEY=你的Supabase匿名密钥 - 同步更新
supabase.ts中的变量引用:const supabaseUrl = import.meta.env.PUBLIC_SUPABASE_URL; const supabaseAnonKey = import.meta.env.PUBLIC_SUPABASE_ANON_KEY; - 重启Astro开发服务器,确保环境变量生效。
2. 修复移动端菜单无响应问题
- 直接在组件顶层调用
checkUser()会导致组件重复渲染,且可能在hydration阶段出错,影响交互逻辑。将checkUser()放入useEffect中:useEffect(() => { const fetchSession = async () => { // 解构session数据,避免判断逻辑错误 const { data: { session } } = await supabase.auth.getSession(); setLoggedIn(!!session); }; fetchSession(); // 可选:监听Auth状态变化,实时更新登录状态 const { data: listener } = supabase.auth.onAuthStateChange((_event, session) => { setLoggedIn(!!session); }); // 组件卸载时取消监听 return () => listener?.unsubscribe(); }, []); - 删除组件顶层的
checkUser()调用。
3. 确保组件正确hydrate
- 在Astro页面中使用Navbar组件时,必须添加客户端指令(如
client:load),确保组件在客户端被激活:<Navbar client:load />
内容的提问来源于stack exchange,提问作者shub
相关产品推荐
相关产品推荐

