如何在Next 13.4中创建一个门户/模态窗口

huangapple go评论70阅读模式
英文:

How to create a portal/modal in Next 13.4

问题

  1. 我想在NextJS 13.4中创建一个Modal(使用新的layout.tsx文件系统),但我无法做到。由于这是一个新功能,我在网上也找不到解决方案。

这是我尝试过的事情:

编辑

  1. 在解决方案中:
import React from "react";
import { createPortal } from "react-dom";

const Modal = () => {
    return createPortal(
        <React.Fragment>
            <div>你的内容</div>
        </React.Fragment>,
        document.body as HTMLElement
    );
};

export default Modal;

它会抛出:

document is not defined

尝试导入Document从'next/document',但仍然不起作用。

另一个错误是error Error: createPortal was called on the server. Portals are not currently supported on the server. Update your program to conditionally call createPortal on the client only.

我在第一行添加了"use client",解决了这个错误。

但仍然无法显示模态框内容。

  1. 如何在Next Js中创建一个门户

由于这个教程的第一步是告诉你创建一个_document文件并在那里放置一个具有特定ID的门户元素,我在Layout.tsx中执行了这个操作(我认为这与document文件相同)。

结果是:水合错误

  1. 其他教程也导致了相同的问题。

请提供一个有效的答案。我知道如何在React或之前的Next版本中创建门户。这是一个在最新版本中发生了不小变化的新版本。

英文:

I wanted to create a Modal in NextJS 13.4 (with the new layout.tsx file system), But I couldn't. since this is a new thing I couldn't find a solution on the web either.

Here are the things that I've tried:

Edit:

  1. In the solutions:
import React from &quot;react&quot;;
import { createPortal } from &quot;react-dom&quot;;

const Modal = () =&gt; {
    return createPortal(
        &lt;React.Fragment&gt;
            &lt;div&gt;your content&lt;/div&gt;
        &lt;/React.Fragment&gt;,
        Document.body as HTMLElement
    );
};

export default Modal;

It will throw:
> document is not defined

Tried to import Document from 'next/document' but still not working.

Another Error was error Error: createPortal was called on the server. Portals are not currently supported on the server. Update your program to conditionally call createPortal on the client only.

I've added "use client" on the first line and it will solve that error.

But still no results in showing that modal content.

  1. How to create a portal in Next Js

Since the step 1 of this tutorial is telling to create a _document file and place your portal element with a specific ID there, I did this in Layout.tsx (I think its the same as document file).

如何在Next 13.4中创建一个门户/模态窗口

Resulted in: Hydration Error

  1. Other tutorials also resulted the same...

Please provide a valid answer. I know how to create a portal in react or previous versions of next. This is a new version that has been changed insignificantly.

答案1

得分: 9

  1. 使用 &quot;use client&quot; 注解将您的 Modal 声明为客户端组件。

  2. 只有在组件在客户端上挂载后才渲染其子元素。

&quot;use client&quot;;

import * as React from &quot;react&quot;;
import { createPortal } from &quot;react-dom&quot;;

export default function Modal({ children }: React.PropsWithChildren) {
  const [mounted, setMounted] = React.useState(false);

  React.useEffect(() =&gt; setMounted(true), []);

  return mounted ? createPortal(&lt;&gt;{children}&lt;/&gt;, document.body) : null;
}
英文:
  1. Declare your Modal as a client component by adding the &quot;use client&quot; annotation

  2. Render its children only when the component has mounted on the client.

&quot;use client&quot;;

import * as React from &quot;react&quot;;
import { createPortal } from &quot;react-dom&quot;;

export default function Modal({ children }: React.PropsWithChildren) {
  const [mounted, setMounted] = React.useState(false);

  React.useEffect(() =&gt; setMounted(true), []);

  return mounted ? createPortal(&lt;&gt;{children}&lt;/&gt;, document.body) : null;
}

答案2

得分: 1

当使用Igor提供的上述代码时,以防不清楚,您的内容应放在这里:<>{children}</>。

例如:

    "use client";
    
    import * as React from "react";
    import { createPortal } from "react-dom";
    
    export default function Modal() {
      const [mounted, setMounted] = React.useState(false);
    
      React.useEffect(() => setMounted(true), []);
    
      return mounted ? createPortal(<div>your content</div>, document.body) : null;
    }
英文:

When using the above code by Igor, in case it's not clear, your content goes here: <>{children}</>.

For Example:

&quot;use client&quot;;

import * as React from &quot;react&quot;;
import { createPortal } from &quot;react-dom&quot;;

export default function Modal() {
  const [mounted, setMounted] = React.useState(false);

  React.useEffect(() =&gt; setMounted(true), []);

  return mounted ? createPortal(&lt;div&gt;your content&lt;/div&gt;, document.body) : null;
} 

答案3

得分: 0

This solution is cool for a simple app, but how do you do when you have Providers / Navbar / Footer already nested in the body element? Here's an example as I can't manage to make it work properly, it keeps being generated outside of the body element:

export default function RootLayout({ children }) {

  return (
    <html lang="en">
      <body className={playfairDisplay.className}>
        <Providers>
          <PolyNav />
          <div id="content-container" style={{ marginTop: "5.5rem" }}>
            {children}
          </div>
          <Footer />
        </Providers>
      </body>
    </html>
  );
}

如何在Next 13.4中创建一个门户/模态窗口

英文:

This solution is cool for a simple app, but how do you do when you have Providers / Navbar / Footer already nested in the body element? Here's an example as I can't manage to make it work properly, it keeps being generated outside of the body element:

  export default function RootLayout({ children }) {

  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body className={playfairDisplay.className}&gt;
        &lt;Providers&gt;
          &lt;PolyNav /&gt;
          &lt;div id=&quot;content-container&quot; style={{ marginTop: &quot;5.5rem&quot; }}&gt;
            {children}
          &lt;/div&gt;
          &lt;Footer /&gt;
        &lt;/Providers&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}

如何在Next 13.4中创建一个门户/模态窗口

答案4

得分: -1

你可以使用 react-dom 的 createPortal 方法来实现。

import React from "react";
import { createPortal } from "react-dom";

export interface ModalProps {
  open: boolean;
  onClose: () => void;
}

const Modal: React.FC<ModalProps> = ({ open, onClose }) => {
  if (!open) return null;

  return createPortal(
    <React.Fragment>
      <div>
        你的内容
      </div>
    </React.Fragment>,
    document.body as HTMLElement
  );
};

export default Modal;

注意:我只提供了代码部分的翻译,没有包含其他内容。

英文:

you can use react-dom create portal

    import React from &quot;react&quot;;
    import { createPortal } from &quot;react-dom&quot;;

export interface ModalProps {
  open: boolean;
  onClose: () =&gt; void;
  
}

const Modal: React.FC&lt;ModalProps&gt; = ({ open, onClose }) =&gt; {
  

  if (!open) return null;

  return createPortal(
    &lt;React.Fragment&gt;
      &lt;div&gt;
        your content
      &lt;/div&gt;
    &lt;/React.Fragment&gt;,
    document.body as HTMLElement
  );
};

export default Modal;

huangapple
  • 本文由 发表于 2023年5月17日 14:02:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76268977.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定