React Native中Formik封装DateTimePicker的选中日期传递问题
React Native + Formik 封装 DateTimePicker 日期无法传递问题修复
问题描述
在React Native中使用Formik封装DateTimePicker组件时,选中日期后无法将值同步到Formik表单中。虽然控制台能打印出选中的日期,但表单仍提示该字段无值错误。
现有代码
AppDatePicker.js
function AppDatePicker({ icon, placeholder, }) { const [date, setDate] = useState(new Date()); const [mode, setMode] = useState(); const [show, setShow] = useState(false); const [title, setTitle] = useState(placeholder) const onChange = (selectedDate) => { const currentDate = selectedDate || date; setShow(Platform.OS === 'ios'); setDate(currentDate); let tempDate = new Date(currentDate); let fDate = tempDate.getFullYear() + '-' + (tempDate.getMonth() + 1) + '-' + tempDate.getDate(); console.log(fDate) setTitle(fDate.toString()) } const showMode = (currentMode) => { setShow(true); setMode(currentMode); } return ( <View> <TouchableWithoutFeedback onPress={() => showMode('date')}> <View style={styles.container}> {icon && <MaterialCommunityIcons name={icon} size={20} color={colors.black} style={styles.icon}> </MaterialCommunityIcons> } { onChange ? ( <AppText style={styles.text}>{title}</AppText> ) : ( <AppText style={styles.placeholder}>{placeholder}</AppText> ) } <MaterialCommunityIcons name="chevron-down" size={20} color={colors.black}></MaterialCommunityIcons> </View> </TouchableWithoutFeedback> {show && <DateTimePicker value={date} mode={mode} display='default' onChange={(_, date) => onChange(date)} onPress={date}> </DateTimePicker> } </View> ); }
AppFormDate.js
import React from 'react'; import { useFormikContext } from 'formik'; import AppErrorMessage from './AppErrorMessage'; import AppDatePicker from './AppDatePicker'; function AppFormDate({ name, placeholder }) { const {errors, setFieldValue, touched, values} = useFormikContext(); return ( <React.Fragment> <AppDatePicker onSelectItem={(date) => setFieldValue(name, date)} placeholder={placeholder} selectedItem={values[name]}> </AppDatePicker> <AppErrorMessage error={errors[name]} visible={touched[name]}> </AppErrorMessage> </React.Fragment> ); }
问题原因及修复方案
核心问题
- 未传递选中日期到父组件:AppDatePicker内部处理了日期选择逻辑,但未调用父组件传入的
onSelectItem回调,导致Formik的setFieldValue从未触发。 - 本地状态未同步表单初始值:AppDatePicker的
date状态始终初始化为当前日期,未同步Formik表单中的已有值,显示与表单值不一致。 - 标题显示逻辑错误:用
onChange是否存在判断显示标题或占位符,逻辑完全不合理,应根据是否选中有效日期判断。
修复后的代码
修复后的AppDatePicker.js
function AppDatePicker({ icon, placeholder, selectedItem, onSelectItem }) { // 用父组件传入的selectedItem初始化本地状态,无值则用当前日期 const [date, setDate] = useState(selectedItem || new Date()); const [mode, setMode] = useState(); const [show, setShow] = useState(false); // 根据选中状态初始化标题 const [title, setTitle] = useState(selectedItem ? `${selectedItem.getFullYear()}-${selectedItem.getMonth() + 1}-${selectedItem.getDate()}` : placeholder ); const onChange = (selectedDate) => { const currentDate = selectedDate || date; setShow(Platform.OS === 'ios'); setDate(currentDate); const fDate = `${currentDate.getFullYear()}-${currentDate.getMonth() + 1}-${currentDate.getDate()}`; console.log(fDate); setTitle(fDate); // 调用父组件回调传递选中日期 if (onSelectItem) { onSelectItem(currentDate); } } const showMode = (currentMode) => { setShow(true); setMode(currentMode); } return ( <View> <TouchableWithoutFeedback onPress={() => showMode('date')}> <View style={styles.container}> {icon && <MaterialCommunityIcons name={icon} size={20} color={colors.black} style={styles.icon} /> } {/* 根据是否选中日期切换显示内容 */} {selectedItem || (date && date.toString() !== new Date().toString()) ? ( <AppText style={styles.text}>{title}</AppText> ) : ( <AppText style={styles.placeholder}>{placeholder}</AppText> )} <MaterialCommunityIcons name="chevron-down" size={20} color={colors.black} /> </View> </TouchableWithoutFeedback> {show && <DateTimePicker value={date} mode={mode} display='default' onChange={(_, selectedDate) => onChange(selectedDate)} /> } </View> ); }
修复后的AppFormDate.js
import React from 'react'; import { useFormikContext } from 'formik'; import AppErrorMessage from './AppErrorMessage'; import AppDatePicker from './AppDatePicker'; function AppFormDate({ name, placeholder, icon }) { const { errors, setFieldValue, touched, values } = useFormikContext(); return ( <> <AppDatePicker icon={icon} placeholder={placeholder} selectedItem={values[name]} onSelectItem={(selectedDate) => { setFieldValue(name, selectedDate); }} /> <AppErrorMessage error={errors[name]} visible={touched[name]} /> </> ); }
关键修复点说明
- 触发父组件回调:AppDatePicker接收
onSelectItem属性,在日期选中后调用该回调,将日期传递给AppFormDate,进而更新Formik表单值。 - 同步表单初始值:用Formik中的
values[name]初始化AppDatePicker的本地date状态,确保显示与表单值一致。 - 修正标题显示逻辑:根据是否存在选中日期切换显示标题或占位符,替代原错误逻辑。
- 移除无效属性:删除DateTimePicker上无意义的
onPress属性。
内容的提问来源于stack exchange,提问作者pyrochan157
相关产品推荐
相关产品推荐

