简答:
React 保证在 refscomponentDidMount
或componentDidUpdate
hooks之前设置。但仅适用于实际渲染的儿童。
componentDidMount() {
// can use any refs here
}
componentDidUpdate() {
// can use any refs here
}
render() {
// as long as those refs were rendered!
return <div ref={/* ... */} />;
}
请注意,这并不意味着“React 总是在这些钩子运行之前设置所有引用”。
让我们看一些没有设置refs 的例子。
不会为未呈现的元素设置 Refs
React 只会为您实际从 render 返回的元素调用 ref 回调。
这意味着如果你的代码看起来像
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
首先看到attached,然后componentDidUpdate
才会触发。
注意其他组件
请注意,如果您将带有 refs 的子组件传递给其他组件,则它们可能会阻止渲染(并导致问题)。
例如,这个:
<MyPanel>
<div ref={this.setRef} />
</MyPanel>
如果MyPanel
不包含props.children
在其输出中,则不会工作:
function MyPanel(props) {
// ignore props.children
return <h1>Oops, no refs for you today!</h1>;
}
再说一次,这不是一个错误:React 不会将 ref 设置为因为 DOM 元素没有被创建。
如果将 Refs 传递给嵌套,则它们不会在生命周期之前设置 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
用来存储 refs
确保您没有使用setState
将 ref 存储在 ref 回调中,因为它是异步的,并且在“完成”之前,componentDidMount
将首先执行。
仍然是一个问题?
如果以上提示都没有帮助,请在 React 中提交问题,我们将查看。