componentDidMount调用BEFORE引用回调 [英] componentDidMount called BEFORE ref callback
问题描述
问题
我正在设置反应 ref
I'm setting a react ref
using an inline function definition
render = () => {
return (
<div className="drawer" ref={drawer => this.drawerRef = drawer}>
然后在 componentDidMount
未设置DOM引用
then in componentDidMount
the DOM reference is not set
componentDidMount = () => {
// this.drawerRef is not defined
我的理解是在mount期间应该运行 ref
回调,但是添加 console.log
语句显示 componentDidMount
在 回调函数之前被称为。
My understanding is the ref
callback should be run during mount, however adding console.log
statements reveals componentDidMount
is called before the ref callback function.
其他代码示例我看过例如这个讨论在github上表明同样的假设, componentDidMount
在渲染中定义的任何
ref
回调之后应该被称为 c $ c>,它甚至在对话中说明了
Other code samples I've looked at for example this discussion on github indicate the same assumption, componentDidMount
should be called after any ref
callbacks defined in render
, it's even stated in the conversation
因此,所有参考后,componentDidMount都会被触发回调已执行
?
So componentDidMount is fired off after all the ref callbacks have been executed?
是。
我正在使用react 15.4.1
I'm using react 15.4.1
我试过的其他东西
为了验证正在调用 ref
函数,我尝试在类上定义它
To verify the ref
function was being called, I tried defining it on the class as such
setDrawerRef = (drawer) => {
this.drawerRef = drawer;
}
然后在渲染
<div className="drawer" ref={this.setDrawerRef}>
在这种情况下,控制台记录显示回调确实被称为 componentDidMount
Console logging in this case reveals the callback is indeed being called after componentDidMount
推荐答案
简答:
React保证在 componentDidMount
或 componentDidUpdate
挂钩之前设置引用。但仅适用于实际已渲染的儿童 。
React guarantees that refs are set before componentDidMount
or componentDidUpdate
hooks. But only for children that actually got rendered.
componentDidMount() {
// can use any refs here
}
componentDidUpdate() {
// can use any refs here
}
render() {
// as long as those refs were rendered!
return <div ref={/* ... */} />;
}
注意这并不意味着React总是设置 all refs在这些钩子运行之前。
让我们看一下refs 没有设置的一些例子。
Note this doesn’t mean "React always sets all refs before these hooks run".
Let’s look at some examples where the refs don’t get set.
React只会为元素调用ref回调你实际上从渲染中返回。
React will only call ref callbacks for elements that you actually returned from render.
这意味着如果您的代码看起来像
This means that if your code looks like
render() {
if (this.state.isLoading) {
return <h1>Loading</h1>;
}
return <div ref={this._setRef} />;
}
最初 this.state.isLoading
是 true
,你应该不期望 this._setRef
被调用在 componentDidMount
之前。
and initially this.state.isLoading
is true
, you should not expect this._setRef
to be called before componentDidMount
.
这应该是有意义的:如果你的第一个渲染返回< h1> ;加载< / h1>
,React无法知道在某些其他条件下它会返回需要附加ref的其他内容。还有无需设置参考: < div>
元素未创建,因为 render()
方法表示它不应该呈现。
This should make sense: if your first render returned <h1>Loading</h1>
, there's no possible way for React to know that under some other condition it returns something else that needs a ref to be attached. There is also nothing to set the ref to: the <div>
element was not created because the render()
method said it shouldn’t be rendered.
所以在这个例子中,只有 componentDidMount
会开枪。但是,当 this.state.loading
更改为 false
时,您会看到 this._setRef
首先附加,然后 componentDidUpdate
将触发。
So with this example, only componentDidMount
will fire. However, when this.state.loading
changes to false
, you will see this._setRef
attached first, and then componentDidUpdate
will fire.
注意如果你将带有refs的孩子传递给其他组件他们有可能做一些阻止渲染的事情(导致问题)。
Note that if you pass children with refs down to other components there is a chance they’re doing something that prevents rendering (and causes the issue).
例如,这个:
<MyPanel>
<div ref={this.setRef} />
</MyPanel>
如果 MyPanel
没有在其输出中包含 props.children
:
wouldn't work if MyPanel
did not include props.children
in its output:
function MyPanel(props) {
// ignore props.children
return <h1>Oops, no refs for you today!</h1>;
}
同样,这不是一个错误: React没有任何内容将ref设置为因为未创建DOM元素。
Again, it’s not a bug: there would be nothing for React to set the ref to because the DOM element was not created.
与上一节类似,如果你将带有ref的孩子传递给另一个组件,这个组件可能会做一些阻止及时附加参考的东西。
Similar to the previous section, if you pass a child with a ref to another component, it’s possible that this component may do something that prevents attaching the ref in time.
例如,也许它不会让孩子回来来自 render()
,而是在生命周期钩子中调用 ReactDOM.render()
。您可以在此处找到此 的示例。在该示例中,我们呈现:
For example, maybe it’s not returning the child from render()
, and instead is calling ReactDOM.render()
in a lifecycle hook. You can find an example of this here. In that example, we render:
<MyModal>
<div ref={this.setRef} />
</MyModal>
但 MyModal
执行 ReactDOM.render()
在中调用 componentDidUpdate
生命周期方法:
But MyModal
performs a ReactDOM.render()
call in its componentDidUpdate
lifecycle method:
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
自React 16起,在生命周期内进行此类顶级渲染调用将推迟到整个树的生命周期运行。这可以解释为什么你没有及时看到附件。
Since React 16, such top-level render calls during a lifecycle will be delayed until lifecycles have run for the whole tree. This would explain why you’re not seeing the refs attached in time.
这个问题的解决方案是使用
门户而不是嵌套 ReactDOM.render
来电:
The solution to this problem is to use
portals instead of nested ReactDOM.render
calls:
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
这样我们的< div> $带有ref的c $ c>实际上包含在渲染输出中。
This way our <div>
with a ref is actually included in the render output.
因此,如果遇到此问题,则需要验证组件与ref之间没有任何内容可能会延迟呈现孩子。
So if you encounter this issue, you need to verify there’s nothing between your component and the ref that might delay rendering children.
确保你没有使用 setState
将ref存储在ref回调中,因为它是异步的,在它完成之前, componentDidMount
将首先执行。
Make sure you are not using setState
to store the ref in ref callback, as it's asynchronous and before it's "finished", componentDidMount
will be executed first.
如果上述提示均无效,请在React中提出问题,我们会一起来看看。
If none of the tips above help, file an issue in React and we will take a look.
这篇关于componentDidMount调用BEFORE引用回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!