You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>
    );
}

问题原因及修复方案

核心问题

  1. 未传递选中日期到父组件:AppDatePicker内部处理了日期选择逻辑,但未调用父组件传入的onSelectItem回调,导致Formik的setFieldValue从未触发。
  2. 本地状态未同步表单初始值:AppDatePicker的date状态始终初始化为当前日期,未同步Formik表单中的已有值,显示与表单值不一致。
  3. 标题显示逻辑错误:用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 04:18:14