【问题标题】:Create React Portal via Ref通过 Ref 创建 React Portal
【发布时间】:2021-10-24 23:46:24
【问题描述】:

我想创建一个 Portal 组件,它应该附加到它的容器组件,但不是通过容器的 ID 而是通过它的 ref。换句话说,我不想将 document.getElementById('CONTAINER_ID') 作为第二个参数传递给 ReactDOM.createPortal 函数,而是仅仅依赖于 React.forwardRef 传递的容器的 ref。 有没有一种简单的方法可以实现这一目标? 否则,也许我需要先创建一个“附加”到 ref 的 dom 节点,然后将节点传递给 createPortal 函数作为第二个参数 ?我想尽可能避免分配 ID。这是示例代码(我在 TypeScript 中工作):

export default React.forwardRef<HTMLDivElement, Props>( (Props, ref) =>{

        const {state, options, dispatch} = Props                     
        if(!state.open) return null
    
        return  ReactDOM.createPortal(
            <div
            className={css`
              height: 140px;
              background: white;
              overflow-y: scroll;
              position: absolute;
              width:100%;
            `}
          >
            {options}
          </div>,
          ref.current // <-- THIS DOESN'T WORK
        )
        
    }    
)

【问题讨论】:

    标签: reactjs react-portal


    【解决方案1】:

    forwardRef 在父组件需要访问子元素时使用,而不是相反。要将元素向下传递给孩子,您将通过道具来完成。此外,由于在第一次渲染之后才会填充 refs,因此您可能需要渲染父组件两次,一次将容器放在页面上,然后再次将其传递给子组件,以便子组件可以创建门户。

    const Parent = () => {
      const ref = useRef<HTMLDivElement>(null);
      const [element, setElement] = useState<HTMLDivElement | null>(null);
      useEffect(() => {
        // Force a rerender, so it can be passed to the child.
        // If this causes an unwanted flicker, use useLayoutEffect instead
        setElement(ref.current); 
      }, []);
    
      return (
        <div ref={ref}>
          {element && (
            <Child element={element} {/* insert other props here */} />
          )}
        </div>
      )
    }
    
    const Child = (props: Props) => {
      const { state, options, dispatch, element } = props;
      if (!state.open) {
        return null;
      }
    
      return ReactDOM.createPortal(
        <div
          className={css`
            height: 140px;
            background: white;
            overflow-y: scroll;
            position: absolute;
            width: 100%;
          `}
        >
          {options}
        </div>,
        element
      );
    }
    

    【讨论】:

    • 您的解决方案有效。到目前为止,我还没有经历过任何闪烁。它似乎工作正常,所以我会回答这个问题。我想知道在创建门户时在状态中使用 refs/storing 元素是否有任何矛盾,因为很难找到有关该主题的任何资源。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2020-07-26
    • 2019-02-05
    • 1970-01-01
    • 2021-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多