我正在创建一个DatePicker并使用useState挂钩来管理它的可见性。在div上单击,我添加了更改值的事件侦听器,但它没有按我预期的那样工作。它只能在第一次使用,因此初始值更改为true,但是在第二次和第三次单击时,此值保持为true,而DatePicker在单击时保持可见。
这是DatePicker
import React, { useState } from 'react';
import OutsideClickHandler from 'react-outside-click-handler';
import { renderInfo, getWeeksForMonth } from './utils';
import {
renderMonthAndYear,
handleBack,
handleNext,
weekdays,
} from '../../utils';
const DatePicker = ({
isOpen,
setIsOpen,
selected,
setSelected,
dayClick,
dayClass,
}) => {
const startDay = new Date().setHours(0, 0, 0, 0);
const [current, setCurrent] = useState(new Date(startDay));
const weeks = getWeeksForMonth(current.getMonth(), current.getFullYear());
function handleClick(date) {
if (date > startDay) {
setSelected(date);
setCurrent(date);
setIsOpen(false);
if (dayClick) {
dayClick(date);
}
}
}
return (
<div className="DatePicker-container">
<div
tabIndex="0"
role="button"
className="DatePicker-info"
onKeyPress={e => {
if (e.which === 13) {
setIsOpen(!isOpen);
}
}}
onClick={e => {
setIsOpen(!isOpen);
}}
>
{renderInfo(selected)}
</div>
{isOpen && (
<OutsideClickHandler onOutsideClick={() => setIsOpen(false)}>
<div className="DatePicker">
<div className="DatePicker__header">
<span
role="button"
onClick={() => handleBack(current, setCurrent)}
className="triangle triangle--left"
/>
<span className="DatePicker__title">
{renderMonthAndYear(current)}
</span>
<span
role="button"
onClick={() => handleNext(current, setCurrent)}
className="triangle triangle--right"
/>
</div>
<div className="DatePicker__weekdays">
{weekdays.map(weekday => (
<div
key={weekday}
className="DatePicker__weekday"
>
{weekday}
</div>
))}
</div>
{weeks.map((week, index) => (
<div
role="row"
key={index}
className="DatePicker__week"
>
{week.map((date, index) =>
date ? (
<div
role="cell"
key={index}
onClick={() => handleClick(date)}
className={dayClass(date)}
>
{date.getDate()}
</div>
) : (
<div
key={index}
className="DatePicker__day--empty"
/>
),
)}
</div>
))}
</div>
</OutsideClickHandler>
)}
</div>
);
};
export default DatePicker;
DateRangePicker,使用两个。
import React, { useState } from 'react';
import DatePicker from './DatePicker';
import DatePickerContext from './DatePickerContext';
import './DatePicker.scss';
const DateRangePicker = () => {
const startDay = new Date().setHours(0, 0, 0, 0);
const [isOpen, setIsOpen] = useState(false);
const [isSecondOpen, setIsSecondOpen] = useState(false);
const [selected, setSelected] = useState(new Date(startDay));
const [secondSelected, setSecondSelected] = useState(new Date(startDay));
function dayClass(date) {
if (
selected.getTime() === date.getTime() ||
(date >= selected && date <= secondSelected)
) {
return 'DatePicker__day DatePicker__day--selected';
}
if (date < startDay || date < selected) {
return 'DatePicker__day DatePicker__day--disabled';
}
return 'DatePicker__day';
}
function dayClick(date) {
setSecondSelected(date);
setIsSecondOpen(true);
}
return (
<DatePickerContext.Provider>
<div className="DatePicker-wrapper">
<DatePicker
key={1}
isOpen={isOpen}
setIsOpen={setIsOpen}
selected={selected}
setSelected={setSelected}
dayClick={dayClick}
dayClass={dayClass}
/>
<DatePicker
key={2}
isOpen={isSecondOpen}
setIsOpen={setIsSecondOpen}
selected={secondSelected}
setSelected={setSecondSelected}
dayClass={dayClass}
/>
</div>
</DatePickerContext.Provider>
);
};
export default DateRangePicker;
答案 0 :(得分:0)
a)好的做法是,当下一个状态取决于上一个(==当前)状态时,使用functional updates确保使用正确的“当前”值:
setIsOpen(currentIsOpen => !currentIsOpen)
b)当下一个状态被针对同一事件执行的多个处理程序更新时,很难推断下一个状态。以下2个处理程序可能会在同一点击上执行(第一个div是“外部”):
<div ... onClick={e => setIsOpen(!isOpen)}>
<OutsideClickHandler onOutsideClick={() => setIsOpen(false)}>
如果先执行onOutsideClick
,然后React用isOpen=false
重新渲染,然后再执行onClick
,那么您将观察到的是isOpen=true
设置-我不会了解如何在两次渲染之间进行重新渲染,但是OutsideClickHandler
可能在做恶作剧,或者您的代码比问题\ _(ツ)_ /¯
仅实施1个事件处理程序:
<OutsideClickHandler onOutsideClick={(e) => {
e.stopPropagation();
setIsOpen(false);
}}>