如何从 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.createPortal
return 返回一个 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
【讨论】:
如果您想将Info
和App
分开,您可以使用this.tooltip.tooltip
从App
访问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?的主要内容,如果未能解决你的问题,请参考以下文章
从 liferay 门户获取 HttpServletResponse
如何生成 Azure O365 API 以获取我们使用 php 在 azure 门户上创建的用户详细信息