
本文旨在解决React Native应用中使用日期选择器时,`getOpenHours`函数被频繁调用以及`openHours`数组被重复更新的问题。通过引入`useEffect`钩子,监听日期变化,并优化数据更新逻辑,有效避免不必要的网络请求和状态更新,提升应用性能和用户体验。
在React Native应用开发中,日期选择器是一个常用的组件。然而,不当的使用方式可能导致性能问题,例如重复的网络请求和状态更新。以下将介绍如何使用useEffect钩子来优化日期选择器的使用,避免这些问题。
问题分析
原始代码中,handleDateChange函数在日期选择器每次值改变时都会被调用,导致getOpeningHours函数被频繁执行,从而发起多次网络请求。此外,由于状态更新的时机不当,openHours数组可能会被重复设置相同的值。
解决方案
核心思想是利用useEffect钩子来监听日期的变化,并在日期真正发生改变时才执行getOpeningHours函数。
- 状态管理优化
首先,引入一个状态变量date来存储选中的日期,并使用setDate函数来更新该状态。
const [date, setDate] = useState();
- 使用useEffect监听日期变化
使用useEffect钩子监听date状态的变化。只有当date状态发生改变时,useEffect内部的函数才会执行。
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();
if(openHours && openHours.length !== 0){
setOpenHours(openHours);
setSelectedStartHour(null);
setSelectedEndHour(null);
setStartHour(null);
setEndHour(null);
}
}
}, [date])这段代码的逻辑如下:
- 当date状态发生改变时,useEffect被触发。
- 首先进行非空判断if (date),确保只有在date有值时才执行后续操作。
- 将日期格式化,并创建Date对象。
- 定义一个内部的async函数getOpeningHours,用于发起网络请求获取开放时间。
- 调用getOpeningHours函数。
- 在获取到openHours后,更新相关状态变量,例如openHours,selectedStartHour,selectedEndHour,startHour和endHour。
- 更新日期选择器回调
在日期选择器的onSelectedChange回调中,只需要更新date状态即可。
return (
setDate(value)}
// other props
/>
) 现在,日期选择器每次值改变时,只会更新date状态,而useEffect会负责监听date的变化,并在日期真正发生改变时才执行getOpeningHours函数。
完整代码示例
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();
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();
if(openHours && openHours.length !== 0){
setOpenHours(openHours);
setSelectedStartHour(null);
setSelectedEndHour(null);
setStartHour(null);
setEndHour(null);
}
}
}, [date])
return (
Select Date
Selected Date is {selectedDate}
setDate(value)}
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...
)}
);注意事项
- 确保正确引入useEffect钩子。
- useEffect的依赖数组中必须包含所有需要在依赖项发生改变时触发的变量,这里是date。
- 在useEffect内部,可以使用async函数来处理异步操作。
总结
通过使用useEffect钩子,可以有效地避免日期选择器导致的重复请求和更新问题,从而提升React Native应用的性能和用户体验。这种方法不仅适用于日期选择器,还可以应用于其他需要监听状态变化并执行副作用的场景。









