React Native中DatePicker出现Maximum update depth exceeded警告求助
解决React Native Modern DatePicker无限更新循环问题
问题根源
- 重复回调触发循环更新:同时给DatePicker绑定
onDateChange和onSelectedChange两个回调,前者更新placeholderDate,后者更新book.date。两个状态的更新都会触发组件重新渲染,DatePicker渲染后又会再次触发回调,形成无限循环,导致「Maximum update depth exceeded」警告。 - 不必要的重复计算:
initialDate在组件每次渲染时都会重新调用getFormatedDate生成,造成性能浪费。
修复方案
- 合并日期选择逻辑,用一个函数同时更新
book.date和placeholderDate,只保留一个DatePicker回调。 - 用
useMemo缓存initialDate,避免重复计算。 - 移除多余的回调函数和属性,简化组件逻辑。
修改后的完整代码
import React, { useEffect, useRef, useState, useMemo } from "react"; import { View, Text, TextInput, Pressable, Alert, TouchableOpacity, Modal, } from "react-native"; import { appFirebase } from "../../../credentials.js"; import { getFirestore, collection, addDoc } from "firebase/firestore"; import { styles } from "../../../styles/styles"; import DatePicker from "react-native-modern-datepicker"; import { getFormatedDate } from "react-native-modern-datepicker"; const db = getFirestore(appFirebase); const Create = (props: { navigation: { navigate: (arg0: string) => void }; }) => { // 捕获输入框值 const [book, setBook] = useState({ title: "", author: "", genre: "", date: "", }); const handleInputOnChangeText = (name: string, value: string) => setBook({ ...book, [name]: value }); // 模态框显示切换 const [visible, setVisible] = useState(false); const handleToggle = () => setVisible(!visible); // 缓存初始日期,避免重复计算 const initialDate = useMemo(() => getFormatedDate(new Date(), "YYYY/MM/DD"), []); const [placeholderDate, setPlaceholderDate] = useState( "Fecha de publicación" ); // 合并日期选择逻辑:同时更新book.date和placeholderDate const handleDateSelect = (selectedDate: string) => { setBook(prev => ({ ...prev, date: selectedDate })); setPlaceholderDate(selectedDate); }; // 判断提交按钮是否禁用 const [isDisabled, setIsDisabled] = useState(true); useEffect(() => { const areFieldsFilled = book.title.trim() !== "" && book.author.trim() !== "" && book.genre.trim() !== "" && book.date.trim() !== ""; setIsDisabled(!areFieldsFilled); }, [book]); // 提交数据到Firebase const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const handleSubmitSavedBook = async () => { try { setLoading(true); const docAdded = await addDoc(collection(db, "library"), { ...book, }); if (!docAdded) { throw new Error("You got a problem adding book"); } console.log("Document written with ID:", docAdded.id); Alert.alert("Your book has been saved!"); props.navigation.navigate("Library"); } catch (err: any) { if (err instanceof Error) { console.error(err.message); } if (err instanceof SyntaxError) { console.error(err.message); } if (err instanceof TypeError) { console.error(err.message); } setError(err); } finally { setLoading(false); } }; // 重置表单 const handleResetForm = () => { setBook({ title: "", author: "", genre: "", date: "" }); setPlaceholderDate("Fecha de publicación"); }; // 自动聚焦第一个输入框 const inputRef = useRef<TextInput>(null); useEffect(() => { inputRef.current?.focus(); }, []); return ( <> <View style={styles.containerCenter}> <Text style={styles.titleText}>AÑADE INFORMACIÓN</Text> {loading && <Text>Is Loading...</Text>} {error && ( <View> <Text>{`${error}`}</Text> </View> )} <View> <TextInput placeholder="Titulo" ref={inputRef} onChangeText={(value) => handleInputOnChangeText("title", value.toLocaleUpperCase()) } value={book.title} /> <TextInput placeholder="Autor" onChangeText={(value) => handleInputOnChangeText("author", value)} value={book.author} /> <TextInput placeholder="Género" onChangeText={(value) => handleInputOnChangeText("genre", value)} value={book.genre} /> <TouchableOpacity onPress={handleToggle}> <Text>{placeholderDate}</Text> </TouchableOpacity> <Modal animationType="fade" transparent={true} visible={visible}> <View style={styles.containerCenter}> <View style={styles.containerModal}> <DatePicker mode="calendar" maximumDate={initialDate} selected={book.date} // 只保留一个回调处理日期选择 onDateChange={handleDateSelect} options={{ backgroundColor: "#080516", textHeaderColor: "#469ab6", textDefaultColor: "white", selectedTextColor: "white", mainColor: "#469ab6", textSecondaryColor: "white", borderColor: "#7a92a51a", }} /> <TouchableOpacity style={styles.button} onPress={handleToggle}> <Text style={styles.buttonText}>Cerrar</Text> </TouchableOpacity> </View> </View> </Modal> </View> <View> <Pressable style={styles.button} onPress={handleSubmitSavedBook} disabled={isDisabled} > <Text style={styles.buttonText}>Guardar</Text> </Pressable> <Pressable style={styles.button} onPress={handleResetForm}> <Text style={styles.buttonText}>Restablecer</Text> </Pressable> <Pressable style={styles.button} onPress={() => props.navigation.navigate("Library")} > <Text style={styles.buttonText}>Volver</Text> </Pressable> </View> </View> </> ); }; export { Create };
关键修改点
- 新增
useMemo缓存initialDate,避免每次渲染重复生成日期字符串。 - 移除
handleInputOnChangeDate和handleChangeInitialDate,替换为handleDateSelect函数,同时更新book.date和placeholderDate。 - DatePicker只保留
onDateChange回调,移除onSelectedChange,避免重复触发状态更新。 - 重置表单时同时重置
placeholderDate为初始提示文本,提升用户体验。
内容的提问来源于stack exchange,提问作者MLT93
相关产品推荐
相关产品推荐

