转发的参考为空

问题描述 投票:0回答:1

我在 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。

reactjs typescript react-hooks react-ref
1个回答
0
投票

确保您的引用被传递到渲染输出(假设它不是

buttonProps
的一部分)。即

return (
  <div
     {...buttonProps}
     role="button"
     ref={innerRef}
     { /* etc */ }
  />
);
© www.soinside.com 2019 - 2024. All rights reserved.