问题
我正在ref使用内联函数定义设置反应
ref
render = () => { return ( <div className="drawer" ref={drawer => this.drawerRef = drawer}>
然后在componentDidMountDOM引用中未设置
componentDidMount
componentDidMount = () => { // this.drawerRef is not defined
我的理解是,ref回调应该在安装期间运行,但是在ref回调函数 之前* 调用添加console.log语句揭示。componentDidMount *
console.log
例如,我看过的其他代码示例在github上的讨论都表明相同的假设,componentDidMount应该在中定义的任何回调 之后ref调用render,甚至在对话中也要说明
render
那么在所有的ref回调都执行完之后,componentDidMount是否被触发? 是。
那么在所有的ref回调都执行完之后,componentDidMount是否被触发?
是。
我正在使用反应 15.4.1
我尝试过的其他事情
为了验证该ref函数是否已被调用,我尝试在此类上定义它
setDrawerRef = (drawer) => { this.drawerRef = drawer; }
然后在 render
<div className="drawer" ref={this.setDrawerRef}>
在这种情况下,控制台日志记录显示确实在 之后* 调用了回调 *componentDidMount
简短答案:
React保证引用被设置在componentDidMount或componentDidUpdate钩子之前。但仅适用于 实际上被渲染 过的孩子 。
componentDidUpdate
componentDidMount() { // can use any refs here } componentDidUpdate() { // can use any refs here } render() { // as long as those refs were rendered! return <div ref={/* ... */} />; }
请注意,这并不意味着“ React总是在运行这些挂钩之前设置 所有 引用”。 让我们看一些 没有 设置参考的示例。
React只会为您实际 从render返回的 元素调用ref回调。
这意味着如果您的代码看起来像
render() { if (this.state.isLoading) { return <h1>Loading</h1>; } return <div ref={this._setRef} />; }
并初步this.state.isLoading是true,你应该 不 希望this._setRef之前调用componentDidMount。
this.state.isLoading
true
this._setRef
这应该是有道理的:如果您的第一个渲染器返回了<h1>Loading</h1>,React无法知道在其他条件下它会返回需要附加引用的其他内容。也 没有将ref设置为的内容:<div>元素未创建,因为render()方法表示不应渲染该元素。
<h1>Loading</h1>
<div>
render()
因此,在此示例中,只会componentDidMount触发。但是,对 进行this.state.loading更改时false,您将this._setRef首先看到附件,然后componentDidUpdate将其触发。
this.state.loading
false
请注意, 如果您将带有ref的子级传递给其他组件 ,则它们可能会执行某些阻止渲染的操作(并导致问题)。
例如,这:
<MyPanel> <div ref={this.setRef} /> </MyPanel>
如果其输出中MyPanel未包含以下内容props.children,则将不起作用:
MyPanel
props.children
function MyPanel(props) { // ignore props.children return <h1>Oops, no refs for you today!</h1>; }
再说一次,这不是一个错误: React没有任何设置引用的原因,因为DOM元素没有创建 。
ReactDOM.render()
与上一节类似,如果将带有ref的孩子传递到另一个组件,则此组件可能会执行某些阻止及时附加ref的操作。
例如,也许不是从中返回子项render(),而是调用ReactDOM.render()了生命周期挂钩。您可以在这里找到一个示例。在该示例中,我们呈现:
<MyModal> <div ref={this.setRef} /> </MyModal>
但是在 其 生命周期方法中MyModal执行ReactDOM.render()调用: __componentDidUpdate
MyModal
componentDidUpdate() { ReactDOM.render(this.props.children, this.targetEl); } render() { return null; }
从React 16开始, 生命周期内的 此类 顶级渲染调用将被延迟,直到整个树的生命周期都已运行为止 。这可以解释为什么您没有及时看到引用。
解决此问题的方法是使用 门户网站而不是嵌套ReactDOM.render调用:
ReactDOM.render
render() { return ReactDOM.createPortal(this.props.children, this.targetEl); }
这样<div>,带有ref的我们实际上包含在渲染输出中。
因此,如果遇到此问题,则需要验证组件和ref之间没有任何东西可能会延迟渲染子级。
setState
确保您setState不习惯将ref存储在ref回调中,因为它是异步的,并且在“完成”之前componentDidMount将首先执行。
如果以上提示均无济于事,请在React中提出问题,我们将进行调查。