首页 > 解决方案 > React - componentDidUpdate() 无法找到 render() 方法渲染的 DOM 对象

问题描述

编辑:我编辑了代码以添加和使用 refs 而不是document.getElementById. 它没有解决问题。

编辑 2:所以我做了一些测试mutationObserver,结果是在节点实际插入之前componentDidUpdate()大约 100 毫秒开始执行!这绝对是问题所在。

但是,React 文档说只有在完全执行完成componentDidUpdate()后才会触发?render()我在这里错过了什么吗?如果是这样,是什么?我想要的只是在插入所有节点执行我的代码。render()

编辑3:问题已被发现并修复。请参阅我在下面发布的答案。感谢所有帮助过的人。


所以我正在尝试为我的网站创建一个登录对话框。我正在利用 React 构建对话框和 FirebaseUI 来显示内容。我的问题是,在 React 通过render()状态更改方法(从open: falseto open: true)渲染 DOM 节点后,该componentDidUpdate()函数无法立即找到这些 DOM 节点。

class SignInModal extends React.Component {

  constructor(props) {
    super(props);
    this.dialogTitle = React.createRef();
    this.firebaseContainer = React.createRef();
  }
  state = {
    open: false,
    redirect: null,
    preRedirectFunction: null,
  };

  handleClickOpen = (redirect, preRedirectFunction) => {    

    this.setState({
      open: true,
      redirect: redirect,
      preRedirectFunction: preRedirectFunction,
    });

  }

  componentDidUpdate() {
    console.log("componentDidUpdate at time: ");
    console.log(Date.now());
    console.log("Sign in modal state: ")
    console.log(this.state);

    console.log("Dialog title: ")
    console.log(this.dialogTitle.current);
    console.log("Firebase container: ")
    console.log(this.firebaseContainer.current);

    /* setTimeout(function () {
      var authUI = firebaseui.auth.AuthUI.getInstance();
    if(authUI){
      console.log("AuthUI found");
      authUI.reset();
      authUI.start('#firebaseui-auth-container', getUIConfig(authUI, SignInModalRendered.state.redirect,SignInModalRendered.state.preRedirectFunction));
    }
    else{
      console.log("No AuthUI found");
      startFirebaseUI("", SignInModalRendered.state.preRedirectFunction);
    }
    }, 200); */


  }

  handleClose = () => {
    this.setState({
      open: false,
      redirect: null,
      preRedirectFunction: null,
    });
  };

  render() {
    console.log("Rendering sign-in modal");
    console.log("Sign in modal state: ")
    console.log(this.state);

    console.log("Dialog title: ")
    console.log(this.dialogTitle.current);
    console.log("Firebase container: ")
    console.log(this.firebaseContainer.current);
    return (
      <div>
        <Dialog
          onClose={this.handleClose}
          aria-labelledby="customized-dialog-title"
          open={this.state.open}
        >
          <DialogTitle id="customized-dialog-title" ref={this.dialogTitle} onClose={this.handleClose} style={{textAlign: "center"}}>
          {Date.now()}
          </DialogTitle>
          <DialogContent id="SignInDialogContainer">
            <div id="firebaseui-auth-container" ref={this.firebaseContainer}></div>
            <div id="loader">{Date.now()}</div>
          </DialogContent>
        </Dialog>
      </div>
    );
  }
}

authUI.start('#firebaseui-auth-container'....执行此代码时,由于找不到 DOM 节点,该代码行失败。

使用编辑后的代码,我纯粹是在尝试获取控制台日志componentDidUpdate(),以便能够找到 Dialog Title 和 Firebase Container DOM 节点。他们还是回来了null

DOM 中的 Date.now()

显示 Date.now() 的控制台日志

但是,Date.now()DOM 中的componentDidUpdate()函数和函数的输出(如上图所示)显示其中的代码在componentDidUpdate()DOM 渲染后 2 毫秒执行。那么为什么里面的代码行componentDidUpdate()找不到呢?

我发现在节点完成渲染之前componentDidUpdate()执行了大约 100 毫秒。为什么会这样?在节点完成渲染如何让我的代码执行?

附加信息:我尝试将有问题的代码块放在一个setTimeout延迟为 200 毫秒的函数中,它运行得很好。但我不想使用这种解决方法,我想了解发生了什么。

标签: javascriptreactjs

解决方案


在构造函数中创建 refs。前任:this.refName = React.createRef();

将 ref 分配为组件中的 prop<Component ref={this.refName} />

访问参考文献this.refName.current

class SignInModal extends React.Component {

  constructor (props) {
    super(props);
    this.customizedDialogTitle = React.createRef();
    this.signInDialogContainer = React.createRef();
    this.firebaseuiAuthContainer = React.createRef();
    this.loader = React.createRef();
    this.state = {
      open: false,
      redirect: null,
      preRedirectFunction: null,
    }
  }

  handleClickOpen = (redirect, preRedirectFunction) => {

    this.setState({
      open: true,
      redirect: redirect,
      preRedirectFunction: preRedirectFunction,
    });

  }

  componentDidUpdate() {
    console.log("componentDidUpdate at time: ");
    console.log(Date.now());
    console.log("Sign in modal state: ")
    console.log(this.state);

    console.log("Dialog title: ")
    console.log(this.customizedDialogTitle.current);
    console.log("Firebase container: ")
    console.log(this.firebaseuiAuthContainer.current);

    var authUI = firebaseui.auth.AuthUI.getInstance();
    if(authUI){
      console.log("AuthUI found");
      authUI.reset();
      authUI.start('#firebaseuiAuthContainer', getUIConfig(authUI, this.state.redirect,this.state.preRedirectFunction));
    }
    else{
      console.log("No AuthUI found");
      startFirebaseUI("", this.state.preRedirectFunction);
    }
  }

  handleClose = () => {
    this.setState({
      open: false,
      redirect: null,
      preRedirectFunction: null,
    });
  };

  render() {
    console.log("Rendering sign-in modal");
    console.log("Sign in modal state: ")
    console.log(this.state);

    console.log("Dialog title: ")
    console.log(this.customizedDialogTitle.current);
    console.log("Firebase container: ")
    console.log(this.firebaseuiAuthContainer.current);
    return (
      <div>
        <Dialog
          onClose={this.handleClose}
          aria-labelledby="customized-dialog-title"
          open={this.state.open}
        >
          <DialogTitle ref={this.customizedDialogTitle} id="customized-dialog-title" onClose={this.handleClose} style={{textAlign: "center"}}>
          {Date.now()}
          </DialogTitle>
          <DialogContent ref={this.signInDialogContainer}>
            <div ref={this.firebaseuiAuthContainer}></div>
            <div ref={this.loader}>{Date.now()}</div>
          </DialogContent>
        </Dialog>
      </div>
    );
  }
}

推荐阅读