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

如何在useEffect外部访问其内部数据?React日历组件问题答疑

问题描述

我有一个DateView组件,需要在ChooseCalendar组件中获取它返回的日期。由于要将useState声明的dateType变量传入该组件,我把从DateView获取数据的代码放在了useEffect块里。现在的问题是,在ChooseCalendar组件中没法访问DateView组件props里的onDateTypeChange所存储的值,请问怎么解决?

ChooseCalendar.js 组件代码

import React, { useState, useEffect, useCallback } from 'react';
import DateView from '../components/DateView';

export default function ChooseCalendar(props) {
  const [calendarType, setCalendarType] = useState('day');
  const [calendarView, setCalendarView] = useState(null);
  const [selectedDate, setSelectedDate] = useState(null);

  // Retrieve dropdown value and pass it to props
  const handleCalendarTypeChange = (event) => {
    const newCalendarType = event.target.value;
    setCalendarType(newCalendarType);
    props.onCalendarTypeChange(newCalendarType);
  };

  const handleDateTypeChange = useCallback((date) => {
    setSelectedDate(date);
  }, []);
  
  useEffect(() => {
    let newCalendarView;
    if (calendarType === 'day') {
      newCalendarView = <DateView dateType="day" onDateTypeChange={handleDateTypeChange} />;
    } else if (calendarType === 'week') {
      newCalendarView = <DateView dateType="week" onDateTypeChange={handleDateTypeChange} />;
    } else if (calendarType === 'month') {
      newCalendarView = <DateView dateType="month" onDateTypeChange={handleDateTypeChange} />;
    }
    setCalendarView(newCalendarView);
  }, [calendarType, handleDateTypeChange]);

  useEffect(() => {
    if (selectedDate) {
      props.onDateTypeChange(selectedDate);
      console.log('Calendar selected date : ', selectedDate);
    }
  }, [selectedDate, props.onDateTypeChange]);

  return (
    <section className="border-4 rounded-lg p-2 px-28 bg-red-400 text-slate-800">
      <h2 className="text-xl font-bold">Calendar Settings</h2>
      <p className="font-semibold mb-1">Change your calendar settings</p>
      <select onChange={handleCalendarTypeChange} className="w-56 border-4 rounded p-2 bg-white hover:bg-gray-100 text-slate-800">
        <option value="day">Day View</option>
        <option value="week">Week View</option>
        <option value="month">Month View</option>
      </select>
      {calendarView}
    </section>
  );
}

DateView.js 组件代码

export default function dateViewDisplayer(props){
  const dateType = props.dateType;

  const handleDateTypeChange = (event) => {
    const date = event.target.value;
    props.onDateTypeChange(date);
  };

  if (dateType === 'day'){
    return (
      <section>
        <p className="font-semibold mb-1">Choose your day</p>
        <input onChange={handleDateTypeChange} className="w-56 border-4 rounded p-2 bg-white hover:bg-gray-100 text-slate-800" type="date" />
      </section>
    );
  }

  if (dateType === 'week'){
    return (
      <section>
        <p className="font-semibold mb-1">Choose your week</p>
        <input onChange={handleDateTypeChange} className="w-56 border-4 rounded p-2 bg-white hover:bg-gray-100 text-slate-800" type="week" />
      </section>
    );
  }

  if (dateType === 'month'){
    return (
      <section>
        <p className="font-semibold mb-1">Choose your month</p>
        <input onChange={handleDateTypeChange} className="w-56 border-4 rounded p-2 bg-white hover:bg-gray-100 text-slate-800" type="month" />
      </section>
    );
  }
}
解决方案

问题根源

你用useEffect创建DateView实例并存在state中的写法,会让组件的更新逻辑脱离React正常的渲染流程,导致回调无法正确触发或响应延迟。

具体修改步骤

  1. 删掉创建calendarView的useEffect:不需要把组件实例存在state里,直接在render阶段条件渲染即可。
  2. 在return中直接渲染DateView:根据calendarType的值动态渲染对应的DateView组件,保证props传递和回调触发都符合React的更新机制。
  3. 修正DateView组件命名:React组件要求首字母大写,把dateViewDisplayer改成DateView,避免命名冲突和潜在问题。

修改后的ChooseCalendar.js代码:

import React, { useState, useEffect, useCallback } from 'react';
import DateView from '../components/DateView';

export default function ChooseCalendar(props) {
  const [calendarType, setCalendarType] = useState('day');
  const [selectedDate, setSelectedDate] = useState(null);

  // Retrieve dropdown value and pass it to props
  const handleCalendarTypeChange = (event) => {
    const newCalendarType = event.target.value;
    setCalendarType(newCalendarType);
    props.onCalendarTypeChange(newCalendarType);
  };

  const handleDateTypeChange = useCallback((date) => {
    setSelectedDate(date);
  }, []);

  useEffect(() => {
    if (selectedDate) {
      props.onDateTypeChange(selectedDate);
      console.log('Calendar selected date : ', selectedDate);
    }
  }, [selectedDate, props.onDateTypeChange]);

  return (
    <section className="border-4 rounded-lg p-2 px-28 bg-red-400 text-slate-800">
      <h2 className="text-xl font-bold">Calendar Settings</h2>
      <p className="font-semibold mb-1">Change your calendar settings</p>
      <select onChange={handleCalendarTypeChange} className="w-56 border-4 rounded p-2 bg-white hover:bg-gray-100 text-slate-800">
        <option value="day">Day View</option>
        <option value="week">Week View</option>
        <option value="month">Month View</option>
      </select>
      {/* 直接条件渲染DateView,不再存到state */}
      <DateView dateType={calendarType} onDateTypeChange={handleDateTypeChange} />
    </section>
  );
}

修改后的DateView.js代码:

// 组件名改成首字母大写的DateView
export default function DateView(props){
  const dateType = props.dateType;

  const handleDateTypeChange = (event) => {
    const date = event.target.value;
    props.onDateTypeChange(date);
  };

  if (dateType === 'day'){
    return (
      <section>
        <p className="font-semibold mb-1">Choose your day</p>
        <input onChange={handleDateTypeChange} className="w-56 border-4 rounded p-2 bg-white hover:bg-gray-100 text-slate-800" type="date" />
      </section>
    );
  }

  if (dateType === 'week'){
    return (
      <section>
        <p className="font-semibold mb-1">Choose your week</p>
        <input onChange={handleDateTypeChange} className="w-56 border-4 rounded p-2 bg-white hover:bg-gray-100 text-slate-800" type="week" />
      </section>
    );
  }

  if (dateType === 'month'){
    return (
      <section>
        <p className="font-semibold mb-1">Choose your month</p>
        <input onChange={handleDateTypeChange} className="w-56 border-4 rounded p-2 bg-white hover:bg-gray-100 text-slate-800" type="month" />
      </section>
    );
  }
}

这样修改后,ChooseCalendar就能正常接收DateView传递回来的日期值,onDateTypeChange的回调也能正确触发。

内容的提问来源于stack exchange,提问作者SKYZE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 19:44:55