问题描述
我正在使用 React Calendar https://www.npmjs.com/package/react-calendar 并且我正在使用他们的 ref 属性来操作日期按钮,以便我可以将自定义功能直接添加到日历 DOM(我认为这是唯一真正的方法,因为他们的道具是有限的。如果你们知道更好的方法,请告诉我,这样我就可以停止使用这种方法了!顺便说一句,我知道存在添加 CSS 的 tileClassName,但我想要一些悬停的功能,但我似乎无法理解这些功能把它放在 tileClassName 中)。 react 日历 ref 是对整个日历 div 的引用,而不是 React 组件 :( .
在 react-calendar/src/YearView/Calendar.jsx 中的 Calendar.jsx
return (
<div
className={mergeClassNames(
baseClassName,selectRange && valueArray.length === 1 && `${baseClassName}--selectRange`,showDoubleView && `${baseClassName}--doubleView`,className,)}
ref={inputRef}
>
{this.renderNavigation()}
<div
className={`${baseClassName}__viewContainer`}
onBlur={selectRange ? onMouseLeave : null}
onMouseLeave={selectRange ? onMouseLeave : null}
>
{this.renderContent()}
{showDoubleView && this.renderContent(true)}
</div>
</div>
);
现在在我的自定义日历 js 中,在每个 useEffect 上,我都设置了它,以便当前 Ref 的单击下一个导航按钮更改依赖于 useEffect 的一个月状态,以便可以再次重新触发 useEffect。
const MainCalendar = () => {
const [month,setMonth] = useState(0)
const ref = React.useRef()
useEffect(() => {
// arrows in ref Change State
ref.current.getElementsByClassName('react-calendar__navigation__arrow react-calendar__navigation__next-button')[0].onclick = () => {
setMonth(month + 1)
return
}
console.log(ref.current)
console.log(ref.current.getElementsByClassName('react-calendar__navigation__label')[0].children[0].textContent)
},[month])
return(
<Calendar
inputRef={ref}/>)
}
现在,当我点击这个红色圆圈的箭头按钮时,重新触发确实发生了,因为控制台再次记录了这两个项目,但是如果你检查我的 useEffect 函数,我将同时打印 ref.Current 和一个 ELEMENT参考电流。我选择的这个元素是 Title Month/Year(例如:上图中的 2021 年 7 月)。现在,控制台正在使用新的 2021 年 8 月日期正确打印当前的 ref DOM(第一次控制台打印)(因为导航按钮向上移动了一个月),但是当我使用 getElementByClassName 访问 ref DOM 时,它似乎正在打印前一个 Ref 元素(第二个控制台打印)而不是我需要的当前 Ref 元素标题。 (例如:打印 2021 年 7 月,而应该是 2021 年 8 月)
如何修复它,以便在 useEffect 中访问的 Ref 元素是最新信息(基本上是来自记录的 ref.current 的信息)?即使情况似乎并非如此,打印 ref.current 显示 2021 年 8 月。我需要它在 useEffect 重新触发后恰好是最新的,以便我可以根据当前显示的标题设置条件,但我可以由于这个困境,现在不要这样做。更新这些 ref 元素的最佳方法是什么?谢谢
解决方法
我找到了解决方案。
async function waitForDate(i) {
function dateChanged() {
return new Promise(resolve => {
const observer = new MutationObserver(() => {
resolve()
})
var config = { characterData: true,attributes: false,childList: false,subtree: true }
observer.observe(ref.current.getElementsByClassName('react-calendar__navigation__label')[0].children[0],config)
})
}
await dateChanged()
setMonth(month + i)
}
我在 useEffect 的 onclick 方法中调用了这个 waitForDate 函数。
我创建了一个异步函数,用于观察并等待 ref 元素更改标题元素。一旦触发,我就使用Effect来重新渲染整个东西。
我之前的解决方案似乎没有考虑到,一旦点击导航按钮并重新触发 useEffect ,当前的 Ref 可能仍然是陈旧的。所以我必须先等待并确认我使用的这个功能已经改变了。