React Hooks 和 Material-UI:在 useEffect 中第一次加载时无法获得对话框引用

ben*_*a21 2 dom reactjs material-ui react-hooks

我试图在第一次加载组件时获取对 material-ui 对话框的 DOM 节点的引用,但该引用始终为undefined.

这是我的方法:

import React, { useEffect, useRef } from "react";
import {
  Dialog,
  DialogTitle,
  DialogContent,
  DialogContentText
} from "@material-ui/core";

export default function App() {
  const dialogRef = useRef();

  useEffect(() => {
    console.log("Dialog Ref");
    console.log(dialogRef.current);
  }, []);

  return (
    <Dialog open ref={dialogRef}>
      <DialogTitle>Ref Test Dialog</DialogTitle>
      <DialogContent>
        <DialogContentText>
          Please check the console to see if a ref to this Dialog was logged.
        </DialogContentText>
      </DialogContent>
    </Dialog>
  );
}
Run Code Online (Sandbox Code Playgroud)

材料UI对话框API文档指出,“裁判被转发到根元素,”和我的方法是基于阵营useRef文档,所以它看起来这应该是工作。

事实上,当我对一个<div>元素使用相同的方法时,它确实有效。我是否遗漏了什么,或者这是 Material UI 中的错误?

这是该问题的一个“工作”示例:

https://codesandbox.io/s/hopeful-agnesi-3i0p3?file=/src/App.js

Rya*_*ell 5

Dialog利用 Modal,而Modal利用 Portal。Material-UI 的 Portal 组件使用 React 的createPortal API在父组件的 DOM 层次结构之外渲染 Dialog。

的参数之一createPortal是要在其中呈现的 DOM 节点。Dialog 支持通过容器 prop控制这个 DOM 节点(默认为 document.body)。Material-UI在效果中获取容器的 DOM 节点,然后呈现 Dialog

因此,在组件的初始渲染时,Material-UI 的 Portal 组件将识别容器并触发 Portal 组件的后续渲染,该渲染将实际渲染 Dialog。

您可以使用disablePortal 道具禁用此功能,在这种情况下,Dialog 将立即呈现,并且 ref 将按您的预期工作。

如果您想保留默认的门户行为,您可以将回调函数作为 ref 传递,以便在 ref 首次可用时执行代码。这样做时,重要的是要对收到的论点进行防御。每当引用发生变化时都会调用回调函数,其中包括在卸载期间将其改回 null。

还有一个onRendered 道具,您可以在其中放置此功能;但是文档表明它将在 v5 中被弃用和删除,并使用 ref 代替。

这是沙箱的修改版本,演示了使用 ref 的回调函数:

import React, { useEffect, useRef } from "react";
import {
  Dialog,
  DialogTitle,
  DialogContent,
  DialogContentText
} from "@material-ui/core";

export default function App() {
  const dialogRef = useRef();

  useEffect(() => {
    console.log("Dialog Ref", dialogRef.current);
  }, []);

  return (
    <Dialog
      open
      ref={(node) => {
        dialogRef.current = node;
        // Do your work requiring the node here, but make sure node isn't null.
        console.log("ref function", node);
      }}
      onRendered={() => console.log("onRendered", dialogRef.current)}
      onEntering={() => console.log("onEntering", dialogRef.current)}
      onEntered={() => console.log("onEntered", dialogRef.current)}
    >
      <DialogTitle>Ref Test Dialog</DialogTitle>
      <DialogContent>
        <DialogContentText>
          Please check the console to see if a ref to this Dialog was logged.
        </DialogContentText>
      </DialogContent>
    </Dialog>
  );
}
Run Code Online (Sandbox Code Playgroud)

编辑对话框参考

  • @PenguinBlues 这是一个有效的 Typescript 沙箱:https://codesandbox.io/s/dialog-ref-typescript-3nq4x?file=/demo.tsx (2认同)