componentDidMount调用BEFORE引用回调 [英] componentDidMount called BEFORE ref callback

查看:169
本文介绍了componentDidMount调用BEFORE引用回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

我正在设置反应 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> 实际上包含在渲染输出中。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆