简短答案:
React保证ref设置在之前componentDidMount
或componentDidUpdate
钩子。但仅适用于实际上被渲染过的孩子。
componentDidMount() {
}
componentDidUpdate() {
}
render() {
return <div ref={/* ... */} />;
}
请注意,这并不意味着“反应始终设置所有在运行这些挂钩之前引用”。
让我们看一些没有设置参考的示例。
引用未设置为未渲染的元素
React只会为您实际使用的元素调用ref回调 从render返回的。
这意味着如果您的代码看起来像
render() {
if (this.state.isLoading) {
return <h1>Loading</h1>;
}
return <div ref={this._setRef} />;
}
首先this.state.isLoading
是true
,您应该不希望this._setRef
之前调用componentDidMount
。
这应该是有道理的:如果您的第一个渲染器返回了<h1>Loading</h1>
,React无法知道在其他条件下它会返回需要附加引用的其他内容。也有没有将ref设置为的内容:<div>
元素未创建,因为render()
方法表示不应渲染该元素。
因此,在此示例中,只会componentDidMount
触发。但是,当this.state.loading
更改为时false
,您会看到this._setRef
首先附件,然后componentDidUpdate
将其触发。
提防其他组件
注意 如果您将带有ref的子级传递给其他组件,则它们可能会执行某些阻止渲染的操作(并导致问题)。
例如,这:
<MyPanel>
<div ref={this.setRef} />
</MyPanel>
如果输出中MyPanel
不包含以下内容props.children
,则将不起作用:
function MyPanel(props) {
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
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
从React 16开始 生命周期中的顶级渲染调用将被延迟,直到整个树的生命周期都已运行为止。这可以解释为什么您没有及时看到引用。
解决此问题的方法是使用
门户而不是嵌套ReactDOM.render
调用:
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
这样我们 <div>
,带有ref的我们实际上包含在渲染输出中。
因此,如果遇到此问题,则需要验证组件和ref之间没有任何东西可能会延迟渲染子级。
不要setState
用来存储裁判
确保您setState
不习惯将ref存储在ref回调中,因为它是异步的,并且在“完成”之前componentDidMount
将首先执行。
还是一个问题?
如果以上提示均不能解决问题,请在React中提出问题,我们将进行调查。
this
从类外部的词法作用域中捕获值。尝试摆脱类方法的箭头函数语法,看看是否有帮助。