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

React Native中如何使用date-fns生成年月日下拉选择器真实数据

基于date-fns实现出生日期下拉选择的方案

核心实现思路

不需要手动编写闰年、大小月的判断逻辑,直接调用date-fns内置的日期处理方法生成合法的年/月/日数据源,同时处理年月日选择的联动规则,从根源上避免出现无效日期。

步骤1:引入依赖与工具方法

先安装date-fns依赖,之后在组件文件中引入需要用到的方法:

import { useState, useMemo, useRef } from 'react';
import { View, Text, TouchableOpacity, FlatList, SafeAreaView } from 'react-native';
import { getYear, getDaysInMonth } from 'date-fns';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';

步骤2:生成静态年、月数据源

年份范围可根据业务需求调整,常规出生日期选择支持从当前年份往前推120年即可,月份固定为1-12月:

// 生成年份列表:当前年份往前120年到当前年
const currentYear = getYear(new Date());
const years = useMemo(() => {
  return Array.from({ length: 121 }, (_, i) => {
    const year = currentYear - 120 + i;
    return { num: String(year), key: String(year) };
  });
}, [currentYear]);

// 生成月份列表:1-12月,补零对齐显示格式
const months = useMemo(() => {
  return Array.from({ length: 12 }, (_, i) => {
    const month = i + 1;
    return { num: String(month).padStart(2, '0'), key: String(month) };
  });
}, []);

步骤3:动态生成对应年月的日期列表

日期列表为动态值,会根据选中的年、月自动计算,自动处理闰年2月、大小月的天数差异:

// 存储选中的年月日
const [selectedDate, setSelectedDate] = useState({
  year: '',
  month: '',
  day: ''
});

// 根据选中的年、月生成合法的日期列表
const days = useMemo(() => {
  // 未选年/月时默认按当前年月计算天数,也可根据需求返回空列表
  const targetYear = selectedDate.year ? Number(selectedDate.year) : currentYear;
  const targetMonth = selectedDate.month ? Number(selectedDate.month) - 1 : 0; // date-fns月份从0开始计数
  const dayCount = getDaysInMonth(new Date(targetYear, targetMonth));
  
  return Array.from({ length: dayCount }, (_, i) => {
    const day = i + 1;
    return { num: String(day).padStart(2, '0'), key: String(day) };
  });
}, [selectedDate.year, selectedDate.month, currentYear]);

步骤4:修复原有Dropdown组件的问题

原组件写死了模拟的days数据,未使用传入的data属性,同时状态管理不支持父子联动,修正后核心代码如下:

const Dropdown = ({ label, data, value, onChange }) => {
  const DropdownButton = useRef();
  const [visible, setVisible] = useState(false);

  const toggleFunction = () => {
    setVisible(prev => !prev);
  };

  const onItemPress = item => {
    onChange(item); // 选中值回传给父组件
    setVisible(false);
  };

  const renderItem = ({ item }) => (
    <TouchableOpacity style={styles.item} onPress={() => onItemPress(item)}>
      <Text style={styles.buttonText}>{item.num}</Text>
    </TouchableOpacity>
  );

  const renderDropdown = () => {
    return (
      <SafeAreaView style={styles.dropdown}>
        <FlatList
          data={data} // 替换为传入的动态数据,不再写死模拟值
          renderItem={renderItem}
          keyExtractor={(item) => item.key} // 用数据自带key,避免索引发问题
        />
      </SafeAreaView>
    );
  };

  return (
    <>
    <View style={{zIndex: 10}} >
      <TouchableOpacity
        onPress={toggleFunction}
        ref={DropdownButton}
        style={styles.button}
      >
        <Text style={styles.buttonText}>
          {value === '' ? label : value}
        </Text>
        <MaterialCommunityIcons name="chevron-down" color={'#58abc8'} size={16} />
        {visible ? renderDropdown() : null}
      </TouchableOpacity>
      </View>
        { visible ? <View 
                 style={styles.modal}>
                <TouchableOpacity
                 style ={styles.overlay}
                 onPress={toggleFunction}
                 ></TouchableOpacity>
      </View>: null}
   </>
  );
};

步骤5:页面中引入三个下拉组件实现联动

// 切换年/月时清空已选日期,避免出现2月31日这类无效值
const handleYearChange = (item) => {
  setSelectedDate(prev => ({...prev, year: item.num, day: ''}));
};
const handleMonthChange = (item) => {
  setSelectedDate(prev => ({...prev, month: item.num, day: ''}));
};
const handleDayChange = (item) => {
  setSelectedDate(prev => ({...prev, day: item.num}));
};

// 渲染选择区域
<View style={{flexDirection: 'row', gap: 12}}>
  <Dropdown 
    label="选择年" 
    data={years} 
    value={selectedDate.year} 
    onChange={handleYearChange}
  />
  <Dropdown 
    label="选择月" 
    data={months} 
    value={selectedDate.month} 
    onChange={handleMonthChange}
  />
  <Dropdown 
    label="选择日" 
    data={days} 
    value={selectedDate.day} 
    onChange={handleDayChange}
  />
</View>

注意点

  • date-fns的月份计数从0开始(0代表1月,11代表12月),生成数据和计算天数时要做好数值偏移
  • 切换年/月时必须清空已选的日,避免出现非法日期
  • 如果需要限制最大/最小可选日期(比如禁止选择未来日期),直接在生成年/月/日数组时加过滤条件即可,不需要改动核心逻辑

内容的提问来源于stack exchange,提问作者wafa.A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:18:53