如何从 React 16 门户获取 ref?

Posted

技术标签:

【中文标题】如何从 React 16 门户获取 ref?【英文标题】:How to get ref from a React 16 portal? 【发布时间】:2018-03-20 11:52:02 【问题描述】:

有没有办法从 React 16 门户获取 ref。我尝试了以下方法,但似乎不起作用:

const Tooltip = props => (
  ReactDOM.createPortal(
    <div>props.children</div>,
    // A DOM element
    document.body
  )
);

class Info extends React.Component 
   render() 
      return (
        <Tooltip 
          ref= el => this.tooltip = el 
        >
          My content
        </Tooltip>
      ); 
   

   componentDidMount() 
      console.log(this.tooltip); // undefined
   

我需要ref 来动态计算元素的最终位置!

https://codepen.io/anon/pen/QqmBpB

【问题讨论】:

奇怪的是你用它来渲染到body中。我的意思是,对于门户网站,您首先需要一个有效的 dom 元素? document.body 不是一个有效的 dom 元素吗? 是的,当然。我知道这只是一个例子。但这似乎是您尝试的错误方式。毕竟,门户的根 dom 是您要渲染的那个。我怀疑对于实际渲染 jsx 对象的普通组件 ref 应该仍然有效。你可以试试吗? 我想我遇到了问题。 ReactDOM.createPortalreturn 返回一个 ReactPortal 实例,它是一个有效的 ReactNode 但不是一个有效的 DOM 元素 【参考方案1】:

ReactDOM.createPortal 返回一个ReactPortal 实例,它是一个有效的ReactNode,但不是一个有效的DOM 元素。同时createPortal 将尊重组件上下文。所以我将函数调用移到了 render 方法中,它解决了这个问题。

class Info extends React.Component 
  render() 
    // I moved the portal creation to be here
    return ReactDOM.createPortal(
       // A valid DOM node!!
       <div ref= el => this.tooltip = el >props.children</div>,
       // A DOM element
       document.body
    ); 
  

  componentDidMount() 
     console.log(this.tooltip); // htmlDivElement
  

【讨论】:

如果您想将InfoApp 分开,您可以使用this.tooltip.tooltipApp 访问Info 门户的DOM 节点【参考方案2】:

如果你想用钩子来做,你也可以做

import  createPortal  from 'react-dom'
import React,  useRef  from 'react'

const Portal = ( children ) => 
  const portal = useRef(document.createElement('div'))
  return createPortal(children, portal.current)

此外,在您的确切示例中,您需要使用 forwardRef,因为没有它您无法将 refs 传递给孩子。

const Tooltip = forwardRef((props, ref) => (
  createPortal(
    <div ref=ref>props.children</div>,
    // A DOM element
    document.body
  )
));

const Info = () => 
  const ref = useRef()
  return (
    <Tooltip ref=ref>
      My content
    </Tooltip>
  )

最后一点没有经过测试,但我很确定它会起作用。

【讨论】:

感谢带有 forwardRef + createPortal 的 Hooks 版本。正是我想要的。【参考方案3】:

您需要在 App 组件中使用this.tooltip.props.children 并为 Tooltip 组件使用以下代码:

const appRoot = document.getElementById('app-root');
const tooltipRoot = document.getElementById('tooltip-root');

class Tooltip extends Component 
  constructor(props) 
    super(props);
    // Create a div that we'll render the Tooltip into
    this.el = document.createElement('div');
  

  componentDidMount() 
    // Append the element into the DOM on mount.
    tooltipRoot.appendChild(this.el);
  

  componentWillUnmount() 
    // Remove the element from the DOM when we unmount
    tooltipRoot.removeChild(this.el);
  

  render() 
    // Use a portal to render the children into the element
    return ReactDOM.createPortal(
      // Any valid React child: JSX, strings, arrays, etc.
      this.props.children,
      // A DOM element
      this.el,
    );
  


class App extends React.Component 
      componentDidMount() 
        console.log(this.tooltip.props.children);
      
      render() 
        return (
          <div>
            <Tooltip ref= el => this.tooltip = el >
              My content
            </Tooltip>
          </div>
        );
      
    

ReactDOM.render(<App />, appRoot);

工作演示 https://codepen.io/jorgemcdev/pen/aLYRVQ,基于 Dan Abramov 代码示例 https://codepen.io/gaearon/pen/jGBWpE

【讨论】:

以上是关于如何从 React 16 门户获取 ref?的主要内容,如果未能解决你的问题,请参考以下文章

使用门户动态创建React模式

从 liferay 门户获取 HttpServletResponse

从开发者门户获取团队列表 - 超时

如何生成 Azure O365 API 以获取我们使用 php 在 azure 门户上创建的用户详细信息

将 Azure Function 从门户导入 Visual Studio

是否有任何 PowerShell 脚本或命令可以从 Azure 门户获取租户中所有用户访问角色的报告?