如何在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正常的渲染流程,导致回调无法正确触发或响应延迟。
具体修改步骤
- 删掉创建calendarView的useEffect:不需要把组件实例存在state里,直接在render阶段条件渲染即可。
- 在return中直接渲染DateView:根据calendarType的值动态渲染对应的DateView组件,保证props传递和回调触发都符合React的更新机制。
- 修正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
相关产品推荐
相关产品推荐

