Next.js向Supabase发送时间数据失败,求类型兼容解决方案
Next.js 向 Supabase 提交时间数据失败的解决方案
我在使用 Next.js 向 Supabase 提交时间数据时始终失败,推测是数据类型不符合 Supabase 的要求,但不知道如何修复。尝试用 new Date() 转换类型也没有效果。以下是我的代码:
原 EventForm 组件代码
"use client"; import { useState, useEffect } from "react"; import { Box, TextField, Button, Checkbox, Container, Grid, } from "@mui/material"; import { publishEvent } from "../../utils/supabaseFunction"; import { useRouter } from "next/navigation"; import Link from "next/link"; import dayjs from "dayjs"; import { Session } from "@supabase/auth-helpers-nextjs"; import { supabase } from "@/utils/supabase"; import { start } from "repl"; const EventForm = ({ session }: { session: Session | null }) => { const router = useRouter(); const [title, setTitle] = useState<string>(""); const [description, setDescription] = useState<string>(""); const [date, setDate] = useState<Date | undefined>(); const [start_time, setStart_time] = useState<Date | undefined>(); const [capacity, setCapacity] = useState<string>(""); const [host_id, setHost_id] = useState<string>(""); const [is_published, setIs_Published] = useState<boolean>(false); const user = session?.user; useEffect(() => { const fetchUserId = async () => { try { const { data: users, error } = await supabase .from("profiles") .select(`id`) .eq("id", user?.id) .single(); if (error) { throw error; } setHost_id(users.id); } catch (error) { console.error("Error fetching data:", error); } }; fetchUserId(); }, []); console.log(start_time); const handlePublishEvent = async (e: any) => { e.preventDefault(); await publishEvent( title, description, capacity, date, start_time, host_id, is_published ); router.push("/event"); }; const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { setIs_Published(event.target.checked); }; return ( <> <div> <Container component="main" maxWidth="xs"> {" "} <Box component="form" onSubmit={(e) => handlePublishEvent(e)}> <Grid item xs={12}> <TextField type="text" name="title" value={title} onChange={(e) => setTitle(e.target.value)} /> </Grid> <Grid item xs={12}> <TextField type="text" name="description" value={description} onChange={(e) => setDescription(e.target.value)} /> </Grid> <Grid item xs={12}> <TextField type="date" name="date" value={dayjs(date).format("YYYY-MM-DD")} onChange={(e) => setDate(new Date(e.target.value))} /> </Grid> <Grid item xs={12}> <TextField type="time" name="time" value={dayjs(date).format("HH:mm:ss")} onChange={(e) => setStart_time(new Date(e.target.value))} /> </Grid> <Grid item xs={12}> <TextField type="text" name="capacity" value={capacity} onChange={(e) => setCapacity(e.target.value)} /> </Grid> <Checkbox checked={is_published} onChange={handleChange} inputProps={{ "aria-label": "controlled" }} /> Check <div> <div> <Button variant="contained" type="submit"> {is_published == true ? <>Publish</> : <>Save</>} </Button> </div> <div> <Button variant="text"> <Link href="/event">Back</Link> </Button> </div> </div> </Box> </Container> </div> </> ); }; export default EventForm;
原 publishEvent 函数代码
export const publishEvent = async ( title: string, description: string, capacity: string, date: Date | undefined, start_time: Date | undefined, host_id: string, is_published: boolean ) => { await supabase.from("events").insert({ title: title, description: description, capacity: capacity, date: date, start_time: start_time, host_id: host_id, is_published: is_published, }); };
问题根源
- 时间输入处理错误:
type="time"的输入框返回HH:mm格式字符串,直接用new Date(e.target.value)会生成无效 Date 对象(比如new Date("14:30")返回Invalid Date),Supabase 无法识别。 - 日期与时间未合并:Supabase 的
timestamp类型需要完整的日期时间信息,当前代码将日期和时间拆分为两个独立对象,不符合字段预期。 - 初始值异常:当
date为undefined时,dayjs(date).format("HH:mm:ss")生成无效字符串,导致输入框显示异常。 - 无错误捕获:
publishEvent未处理 Supabase 请求错误,无法定位具体失败原因。
修复方案
修改后的 EventForm 组件
"use client"; import { useState, useEffect } from "react"; import { Box, TextField, Button, Checkbox, Container, Grid, } from "@mui/material"; import { publishEvent } from "../../utils/supabaseFunction"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { Session } from "@supabase/auth-helpers-nextjs"; import { supabase } from "@/utils/supabase"; const EventForm = ({ session }: { session: Session | null }) => { const router = useRouter(); const [title, setTitle] = useState<string>(""); const [description, setDescription] = useState<string>(""); const [date, setDate] = useState<string>(""); // 存储YYYY-MM-DD字符串 const [startTimeStr, setStartTimeStr] = useState<string>(""); // 存储HH:mm字符串 const [capacity, setCapacity] = useState<string>(""); const [host_id, setHost_id] = useState<string>(""); const [is_published, setIs_Published] = useState<boolean>(false); const user = session?.user; useEffect(() => { const fetchUserId = async () => { try { const { data: users, error } = await supabase .from("profiles") .select(`id`) .eq("id", user?.id) .single(); if (error) throw error; setHost_id(users.id); } catch (error) { console.error("获取用户ID失败:", error); } }; if (user) fetchUserId(); // 避免user为undefined时执行 }, [user]); const handlePublishEvent = async (e: React.FormEvent) => { e.preventDefault(); // 合并日期与时间为完整Date对象 const fullStartTime = date && startTimeStr ? new Date(`${date}T${startTimeStr}:00`) : undefined; try { await publishEvent( title, description, capacity, date ? new Date(date) : undefined, fullStartTime, host_id, is_published ); router.push("/event"); } catch (error) { console.error("提交事件失败:", error); } }; const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { setIs_Published(event.target.checked); }; return ( <Container component="main" maxWidth="xs"> <Box component="form" onSubmit={handlePublishEvent}> <Grid item xs={12} mb={2}> <TextField fullWidth type="text" name="title" label="标题" value={title} onChange={(e) => setTitle(e.target.value)} required /> </Grid> <Grid item xs={12} mb={2}> <TextField fullWidth type="text" name="description" label="描述" value={description} onChange={(e) => setDescription(e.target.value)} required /> </Grid> <Grid item xs={12} mb={2}> <TextField fullWidth type="date" name="date" label="日期" value={date} onChange={(e) => setDate(e.target.value)} InputLabelProps={{ shrink: true }} required /> </Grid> <Grid item xs={12} mb={2}> <TextField fullWidth type="time" name="time" label="开始时间" value={startTimeStr} onChange={(e) => setStartTimeStr(e.target.value)} InputLabelProps={{ shrink: true }} required /> </Grid> <Grid item xs={12} mb={2}> <TextField fullWidth type="number" name="capacity" label="容量" value={capacity} onChange={(e) => setCapacity(e.target.value)} required /> </Grid> <Grid item xs={12} mb={2}> <Checkbox checked={is_published} onChange={handleChange} inputProps={{ "aria-label": "是否发布" }} /> 发布事件 </Grid> <Grid container spacing={2}> <Grid item xs={6}> <Button fullWidth variant="contained" type="submit"> {is_published ? "发布" : "保存"} </Button> </Grid> <Grid item xs={6}> <Button fullWidth variant="text"> <Link href="/event">返回</Link> </Button> </Grid> </Grid> </Box> </Container> ); }; export default EventForm;
修改后的 publishEvent 函数
import { supabase } from "@/utils/supabase"; export const publishEvent = async ( title: string, description: string, capacity: string, date: Date | undefined, start_time: Date | undefined, host_id: string, is_published: boolean ) => { const { error } = await supabase.from("events").insert({ title, description, capacity: parseInt(capacity, 10), // 转换为数字匹配数据库integer字段 date, start_time, host_id, is_published, }); if (error) { throw new Error(`Supabase 插入错误: ${error.message}`); } };
额外注意事项
- 确保 Supabase
events表中,date字段类型为date,start_time字段类型为timestamp with time zone或timestamp。 - 若无需拆分日期和时间,可直接使用单个
datetime字段简化逻辑。
内容的提问来源于stack exchange,提问作者Yuki Sakiyama
相关产品推荐
相关产品推荐

