使用React Day Picker与Next.js无法设置初始选中日期
问题解决思路
问题根源
刷新页面时,React Query的异步请求还未返回数据,组件初始化阶段initialDatesTest是undefined,导致useState的初始值为空数组。等请求完成拿到数据后,useState不会自动更新状态,所以选中日期无法显示;而站点内跳转时React Query存在缓存,初始化就能拿到数据,因此显示正常。
解决方案1:用useEffect同步React Query数据到本地state
监听initialDatesTest的变化,当数据加载完成后更新本地days状态:
const { data: initialDatesTest, error, isLoading, } = useQuery({ queryKey: ["dates"], queryFn: getDates, }); async function getDates() { const response = await fetch("/api/dates-to-exclude"); const data = await response.json(); const parsedExcludedDates = data.excludedDates.PartyExcludeDates.map( (dateString: string) => new Date(dateString) ); return parsedExcludedDates; } const [days, setDays] = useState<Date[] | undefined>([]); // 监听React Query数据变化,同步到本地state useEffect(() => { if (initialDatesTest) { setDays(initialDatesTest); } }, [initialDatesTest]); // 渲染部分保留 <Controller control={control} name="DayPicker" render={({ field }) => ( <DayPicker mode="multiple" min={1} selected={days} onSelect={setDays} footer={footer} disabled={{ before: new Date() }} numberOfMonths={1} /> )} />
解决方案2:结合缓存数据与本地交互(更优)
如果用户需要手动修改选中日期,可通过useRef标记初始化状态,避免后续数据更新覆盖用户手动修改的内容:
const { data: initialDatesTest, error, isLoading, } = useQuery({ queryKey: ["dates"], queryFn: getDates, }); async function getDates() { const response = await fetch("/api/dates-to-exclude"); const data = await response.json(); const parsedExcludedDates = data.excludedDates.PartyExcludeDates.map( (dateString: string) => new Date(dateString) ); return parsedExcludedDates; } // 标记是否已经完成初始状态赋值 const hasInitialized = useRef(false); const [days, setDays] = useState<Date[] | undefined>([]); useEffect(() => { if (initialDatesTest && !hasInitialized.current) { setDays(initialDatesTest); hasInitialized.current = true; } }, [initialDatesTest]); // 渲染部分保留 <Controller control={control} name="DayPicker" render={({ field }) => ( <DayPicker mode="multiple" min={1} selected={days} onSelect={setDays} footer={footer} disabled={{ before: new Date() }} numberOfMonths={1} /> )} />
额外提示
如果不需要用户修改选中日期,甚至可以直接用initialDatesTest作为DayPicker的selected值,省去本地state:
<DayPicker mode="multiple" min={1} selected={initialDatesTest || []} footer={footer} disabled={{ before: new Date() }} numberOfMonths={1} />
内容的提问来源于stack exchange,提问作者user10980228
相关产品推荐
相关产品推荐

