问题
我正在使用内联函数定义设置一个 react ref
render = () => {
return (
<div className="drawer" ref={drawer => this.drawerRef = drawer}>
然后在 componentDidMount
中未设置 DOM 引用
componentDidMount = () => {
// this.drawerRef is not defined
我的理解是 ref
回调应该在挂载期间运行,但是添加 console.log
语句显示 componentDidMount
在之前被调用 ref 回调函数。
我看过的其他代码示例(例如 github 上的 this discussion)表明了相同的假设,componentDidMount
应该在任何 ref
回调之后 被调用在render
中定义,甚至是stated in the conversation
So componentDidMount is fired off after all the ref callbacks have been executed?
是的。
我正在使用 React 15.4.1
我尝试过的其他方法
为了验证 ref
函数是否被调用,我尝试在类上定义它
setDrawerRef = (drawer) => {
this.drawerRef = drawer;
}
然后在render
<div className="drawer" ref={this.setDrawerRef}>
在这种情况下,控制台日志显示回调确实在 之后 componentDidMount
最佳答案
简答:
React 保证 refs 设置在 componentDidMount
之前或 componentDidUpdate
钩子(Hook)。但仅限于实际渲染的 child 。
componentDidMount() {
// can use any refs here
}
componentDidUpdate() {
// can use any refs here
}
render() {
// as long as those refs were rendered!
return <div ref={/* ... */} />;
}
请注意,这并不意味着“React 总是在这些钩子(Hook)运行之前设置所有 refs”。
让我们看一些没有设置 refs 的例子。
不会为未呈现的元素设置 Refs
React 只会为您实际<strong>从渲染返回的元素调用 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 的东西。也没有任何东西可以将 ref 设置为: <div>
未创建元素,因为 render()
方法说它不应该被渲染。
所以对于这个例子,只有componentDidMount
会开火。但是,当 this.state.loading
更改为 false
,你会看到this._setRef
先附上,然后是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()
返回 child , 而不是调用 ReactDOM.render()
在生命周期钩子(Hook)中。您可以找到此 here 的示例.在那个例子中,我们呈现:
<MyModal>
<div ref={this.setRef} />
</MyModal>
但是MyModal
执行 ReactDOM.render()
调用它的 componentDidUpdate
生命周期方法:
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
自 React 16 以来,此类生命周期中的顶级渲染调用将被延迟,直到整个树的生命周期运行完毕。这可以解释为什么您没有及时看到附加的引用。
这个问题的解决方案是使用
portals而不是嵌套 ReactDOM.render
调用:
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
这边我们的<div>
具有 ref 实际上包含在渲染输出中。
因此,如果您遇到此问题,您需要确认您的组件和 ref 之间没有任何可能延迟渲染子项的内容。
不要使用setState
存储引用
确保你没有使用 setState
将 ref 存储在 ref 回调中,因为它是异步的并且在它“完成”之前,componentDidMount
将首先执行。
还是个问题?
如果以上提示均无帮助,请在 React 中提交问题,我们将进行查看。
关于javascript - componentDidMount 在 ref 回调之前被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44074747/