javascript - componentDidMount 在 ref 回调之前被调用

标签 javascript reactjs

问题

我正在使用内联函数定义设置一个 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.isLoadingtrue ,你应该期待this._setRefcomponentDidMount之前被调用.

这应该是有道理的:如果您的第一个渲染返回 <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/

相关文章:

javascript - moment.js 第二个参数不起作用

javascript - 如何解决TypeError : arr[Symbol. iterator] is not a function in my React project

javascript - 基金会 Accordion 无法在 React 中工作

javascript - Firebase v.9 deleteDoc( ) 不执行任何操作,也不捕获任何错误

javascript - 如何获取 Kendo Multi Select Control 中所选项目的数量?

javascript - JS 中 Promise 和回调的问题

javascript - 将基础导航与 Bootstrap 合并

javascript - addEventListener 和数组内部的值递减问题

javascript - 在 React + TypeScript 中将函数从容器传递到功能组件

javascript - React.js 切换显示