基于React-Datepicker实现用户专属配送日期展示与禁用功能求助
解决方案:动态展示用户专属配送日并过滤React-Datepicker选项
我会分三个核心部分帮你落地需求:提取用户专属配送配置、计算下一个可用配送日、配置React-Datepicker的日期过滤规则。
1. 从Auth0用户元数据中提取配送日
首先要从Auth0返回的用户对象里拿到对应区域的配送日。假设你的user.user_metadata里存的是类似deliveryDay: "Monday"(星期名称)或者deliveryDay: 1(MomentJS的星期数字,1=周一,0=周日),先统一转换成MomentJS能直接用的星期数字:
import moment from 'moment'; import { useAuth0 } from '@auth0/auth0-react'; // 获取Auth0用户对象 const { user } = useAuth0(); // 转换配送日为Moment兼容的星期数字(0=周日,1=周一...6=周六) const getUserDeliveryDay = () => { const deliveryDay = user?.user_metadata?.deliveryDay; if (!deliveryDay) return null; // 处理字符串格式的星期名称(比如"Monday") if (typeof deliveryDay === 'string') { return moment().day(deliveryDay).day(); } // 已经是数字则直接返回 return Number(deliveryDay); }; const userDeliveryDay = getUserDeliveryDay();
2. 计算下一个可用配送日
接下来要结合当前时间和用户配送日,算出符合规则的下一个配送日——这里要注意当天是否过了配送截止时间(比如公司规定当天12点前下单才能走当天配送,否则要等下一个周期):
// 可根据业务调整配送截止时间 const DELIVERY_CUTOFF_HOUR = 12; const getNextDeliveryDate = () => { if (!userDeliveryDay) return null; const today = moment(); const todayDay = today.day(); const isTodayDeliveryDay = todayDay === userDeliveryDay; const isAfterCutoff = today.hour() >= DELIVERY_CUTOFF_HOUR; let nextDelivery = today.clone().day(userDeliveryDay); // 如果今天是配送日但已过截止时间,或者计算出的日期在今天之前,就往后推一周 if ((isTodayDeliveryDay && isAfterCutoff) || nextDelivery.isBefore(today, 'day')) { nextDelivery.add(7, 'days'); } return nextDelivery; // 返回moment对象,方便后续格式化展示 }; const nextDeliveryDate = getNextDeliveryDate();
然后你就可以把这个日期展示给用户:
{nextDeliveryDate && ( <p>您的下一个配送日:{nextDeliveryDate.format('YYYY年MM月DD日 dddd')}</p> )}
3. 配置React-Datepicker过滤可选日期
React-Datepicker的filterDate属性可以自定义哪些日期可选。我们写一个过滤函数,只允许用户的配送日且是**今天及以后(符合截止时间规则)**的日期:
import DatePicker from 'react-datepicker'; import 'react-datepicker/dist/react-datepicker.css'; import { useState } from 'react'; const [selectedDate, setSelectedDate] = useState(null); // 日期过滤函数 const filterAllowedDates = (date) => { if (!userDeliveryDay) return false; const dateMoment = moment(date); const today = moment(); // 不是用户配送日直接禁用 if (dateMoment.day() !== userDeliveryDay) return false; // 今天之前的日期直接禁用 if (dateMoment.isBefore(today, 'day')) return false; // 如果是今天,判断是否过了截止时间 if (dateMoment.isSame(today, 'day')) { return today.hour() < DELIVERY_CUTOFF_HOUR; } // 符合条件的未来配送日允许选择 return true; }; // 在组件中使用DatePicker <DatePicker selected={selectedDate} onChange={(date) => setSelectedDate(date)} filterDate={filterAllowedDates} dateFormat="yyyy-MM-dd EEEE" placeholderText="选择配送日期" />
优化建议:封装成自定义Hook
把这些逻辑封装成自定义Hook,方便在多个组件中复用,代码也更整洁:
import { useAuth0 } from '@auth0/auth0-react'; import moment from 'moment'; export const useUserDelivery = () => { const { user } = useAuth0(); const DELIVERY_CUTOFF_HOUR = 12; // 获取用户配送日数字 const userDeliveryDay = (() => { const deliveryDay = user?.user_metadata?.deliveryDay; if (!deliveryDay) return null; if (typeof deliveryDay === 'string') { return moment().day(deliveryDay).day(); } return Number(deliveryDay); })(); // 计算下一个配送日 const getNextDeliveryDate = () => { if (!userDeliveryDay) return null; const today = moment(); const todayDay = today.day(); const isTodayDeliveryDay = todayDay === userDeliveryDay; const isAfterCutoff = today.hour() >= DELIVERY_CUTOFF_HOUR; let nextDelivery = today.clone().day(userDeliveryDay); if ((isTodayDeliveryDay && isAfterCutoff) || nextDelivery.isBefore(today, 'day')) { nextDelivery.add(7, 'days'); } return nextDelivery; }; // 日期过滤函数 const filterAllowedDates = (date) => { if (!userDeliveryDay) return false; const dateMoment = moment(date); const today = moment(); if (dateMoment.day() !== userDeliveryDay) return false; if (dateMoment.isBefore(today, 'day')) return false; if (dateMoment.isSame(today, 'day')) { return today.hour() < DELIVERY_CUTOFF_HOUR; } return true; }; return { userDeliveryDay, nextDeliveryDate: getNextDeliveryDate(), filterAllowedDates }; };
在组件里直接调用这个Hook即可:
const { nextDeliveryDate, filterAllowedDates } = useUserDelivery(); // 展示下一个配送日 {nextDeliveryDate && ( <div> <h3>您的下一个配送日:</h3> <p>{nextDeliveryDate.format('YYYY年MM月DD日 dddd')}</p> </div> )} // 使用DatePicker <DatePicker selected={selectedDate} onChange={setSelectedDate} filterDate={filterAllowedDates} dateFormat="yyyy-MM-dd EEEE" />
注意事项
- 确认MomentJS的星期数字和你存储的配送日对应正确(比如
moment().day(1)对应周一,moment().day(0)对应周日)。 - 如果Auth0的
user_metadata里存的是其他格式(比如中文“周一”),需要调整转换逻辑适配。 - 配送截止时间可以改成动态配置,比如从后端接口获取。
内容的提问来源于stack exchange,提问作者Chizzah
相关产品推荐
相关产品推荐

