
本文旨在解决 React Native 应用中使用日期选择器时,`getOpenHours` 函数被快速连续调用多次以及 `openHours` 数组被重复更新的问题。我们将通过使用 `useEffect` 钩子和正确地更新状态来优化代码,确保函数只在日期真正改变时执行,并避免不必要的数据更新。
在 React Native 应用中,使用日期选择器时,可能会遇到 getOpenHours 函数在日期选择后被多次调用的问题,导致不必要的网络请求和性能损耗。同时,openHours 数组也可能被重复更新,影响用户体验。为了解决这些问题,我们需要对代码进行优化,确保函数只在日期真正改变时执行,并避免不必要的数据更新。
使用 useEffect 钩子监听日期变化
useEffect 钩子允许我们在组件渲染后执行副作用操作,例如数据获取、订阅或手动更改 DOM。 我们可以利用它来监听 date 状态的变化,并在日期改变时才调用 getOpeningHours 函数。
const [date, setDate] = useState();
const [openHours, setOpenHours] = useState([]);
useEffect(() => {
if (date){
const formattedDate = date.replace(/\//g, "-");
const selectedDate = new Date(formattedDate);
const getOpeningHours = async () => {
try {
const response = await axios.post(
`https://spacezone-backend.cyclic.app/api/booking/getOpenHours/${placeId}`,
{ Date: date }
);
setOpenHours(response.data.openHoursArray);
} catch (error) {
console.log(error);
}
};
getOpeningHours();
setSelectedStartHour(null);
setSelectedEndHour(null);
setStartHour(null);
setEndHour(null);
}
}, [date, placeId]);代码解释:
- useState(null): 初始化 date 状态,用于存储选中的日期。
- useEffect(() => { ... }, [date, placeId]): useEffect 钩子监听 date 和 placeId 的变化。只有当 date 或 placeId 发生变化时,才会执行回调函数。
- if (date): 确保只有当 date 有值时才执行后续操作。
- getOpeningHours 函数: 定义一个异步函数 getOpeningHours,用于从服务器获取开放时间数据。
- setOpenHours(response.data.openHoursArray): 使用从服务器获取的开放时间数据更新 openHours 状态。
- setSelectedStartHour(null); ...: 重置其他相关状态。
- [date, placeId]: 依赖项数组,指定 useEffect 钩子依赖的状态。只有当这些状态发生变化时,才会重新执行回调函数。 placeId 也应该作为依赖项,因为这个值是从 route.params 中获取的,如果这个值变化了,也应该重新获取数据。
更新日期选择器组件
在日期选择器组件中,只需要更新 date 状态即可。
return (
setDate(value)}
// other props
/>
) 代码解释:
- onSelectedChange={(value) => setDate(value)}: 当日期选择器中的日期发生变化时,调用 setDate 函数更新 date 状态。
完整示例代码
const RoomDetailsPage = ({ route }) => {
const [selectedDate, setSelectedDate] = useState(null);
const [selectedStartHour, setSelectedStartHour] = useState(null);
const [selectedEndHour, setSelectedEndHour] = useState(null);
const [startHour, setStartHour] = useState(null);
const [endHour, setEndHour] = useState(null);
const [isDatePickerVisible, setDatePickerVisible] = useState(false);
const { roomId } = route.params;
const { placeId } = route.params;
const { roomDetails } = route.params;
const startDate = roomDetails.days[0].date.split("T")[0];
const endDate =
roomDetails.days[roomDetails.days.length - 1].date.split("T")[0];
const [openHours, setOpenHours] = useState([]);
const [date, setDate] = useState(null); // 使用新的 date 状态
useEffect(() => {
if (date) {
const formattedDate = date.replace(/\//g, "-");
const selectedDate = new Date(formattedDate);
const getOpeningHours = async () => {
try {
const response = await axios.post(
`https://spacezone-backend.cyclic.app/api/booking/getOpenHours/${placeId}`,
{ Date: date }
);
setOpenHours(response.data.openHoursArray);
} catch (error) {
console.log(error);
}
};
getOpeningHours();
setSelectedStartHour(null);
setSelectedEndHour(null);
setStartHour(null);
setEndHour(null);
}
}, [date, placeId]);
return (
Select Date
Selected Date is {date} {/* 显示 date 状态 */}
setDate(value)} // 更新 date 状态
options={{
backgroundColor: "#090C08",
textHeaderColor: "#FFA25B",
textDefaultColor: "#F6E7C1",
selectedTextColor: "#fff",
mainColor: "#F4722B",
textSecondaryColor: "#D6C7A1",
borderColor: "rgba(122, 146, 165, 0.1)",
}}
current="2023-06-01"
mode="calendar"
minimumDate={startDate}
maximumDate={endDate}
minuteInterval={30}
style={{ borderRadius: 10 }}
/>
{/* List of selectable hours */}
{openHours && openHours.length > 0 ? (
<>
Select Hours
{openHours.map((hour) => (
handleHourPress(hour)}
>
{hour}:00
))}
>
) : (
Loading open hours...
)}
);
};注意事项
- 确保 placeId 在 useEffect 的依赖项数组中,以便在 placeId 发生变化时也能重新获取数据。
- 在 getOpeningHours 函数中处理错误,避免程序崩溃。
- 根据实际需求调整代码,例如添加 loading 状态,优化用户体验。
- axios 需要先安装 npm install axios 或者 yarn add axios
总结
通过使用 useEffect 钩子监听日期变化,并正确地更新状态,我们可以有效地避免 getOpenHours 函数被重复调用以及 openHours 数组被重复更新的问题。 这种方法可以提高 React Native 应用的性能和用户体验。










