我在 React 中有以下转发的参考:
export type AccordionHeaderProps<T extends ElementType> = {
children: React.ReactNode;
asTrigger?: boolean;
subTitle?: React.ReactNode;
chevronProps?: AriaButtonOptions<T>;
} & Options;
export const AccordionHeader = forwardRef(
(
{
children,
asTrigger,
subTitle,
chevronProps,
id,
className,
isVisible,
borderRadius,
isLoading,
error,
isDisabled
}: AccordionHeaderProps<"div">,
ref
) => {
const [accordionItemState, setAccordionItemState] = useContext(AccordionItemContext);
const innerRef = useRef(null);
useImperativeHandle(ref, () => innerRef.current!, []);
const { buttonProps } = useButton(chevronProps || {}, innerRef as React.RefObject<HTMLDivElement>);
const icon = [
<motion.div
animate={{ rotate: accordionItemState.isExpanded ? "-90deg" : "0deg" }}
whileHover={{ background: "#f1f5f9" }}
whileTap={{ scale: 0.9 }}
initial={{ background: "transparent" }}
transition={{ ease: "easeInOut" }}
className="ml-auto rounded-sm"
>
<ChevronLeft width={25} />
</motion.div>,
<div className="ml-auto">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
preserveAspectRatio="xMidYMid"
width="25"
height="25"
style={{ shapeRendering: "auto", display: "block", background: "transparent" }}
>
<g>
<circle
stroke-dasharray="122.52211349000194 42.840704496667314"
r="26"
stroke-width="5"
stroke="#000000"
fill="none"
cy="50"
cx="50"
>
<animateTransform
keyTimes="0;1"
values="0 50 50;360 50 50"
dur="1s"
repeatCount="indefinite"
type="rotate"
attributeName="transform"
></animateTransform>
</circle>
<g></g>
</g>
</svg>
</div>,
<div className="ml-auto">
<AlertCircle width={25} height={25} />
</div>
];
let iconState = 0;
if (isLoading) iconState = 1;
else if (error) iconState = 2;
const onClick = () => {
if (!asTrigger) return;
if (iconState > 0) return;
setAccordionItemState({ isExpanded: !accordionItemState.isExpanded });
if (accordionItemState.isExpanded) innerRef.current.removeAttribute("hidden");
};
return (
<div
{...buttonProps}
role="button"
id={id}
onClick={() => onClick()}
className={header({
class: `${className} ${borderRadius ? `rounded-${borderRadius}` : ""}`,
isDisabled,
isVisible
})}
>
<div>
{children}
<br />
<span className="text-slate-400">{subTitle}</span>
</div>
{icon[iconState]}
</div>
);
}
);
需要注意的部分是
innerRef
。 innerRef.current
是null
。我希望它是一个 DOMRef。然而,当我控制台记录它时,我得到当前的null
。即使将其包裹起来useEffect
,我仍然会得到相同的结果,只需打印两次。
我希望能够使用 ref 来从元素中删除属性并动态地将其添加回来。我仍然希望能够转发并传递参考给
useButton
。理想情况下,我希望通过完整的类型安全来完成此任务(至少对于前向引用中的 ref 属性)。我怎样才能做到这一点。
我正在使用React 18。客户端组件,没有框架。
useButton
钩子来自 React aria。
确保您的引用被传递到渲染输出(假设它不是
buttonProps
的一部分)。即
return (
<div
{...buttonProps}
role="button"
ref={innerRef}
{ /* etc */ }
/>
);