reactjs React-18|您正在对之前已传递给createRoot()的容器调用ReactDOMClient.createRoot(

pexxcrt2  于 2023-03-12  发布在  React
关注(0)|答案(5)|浏览(362)

在我的基于React的库中,我在3个不同的级别使用ReactDOM.render。第一个级别是根级别,我很清楚,并使用以下代码替换它:

import { createRoot } from 'react-dom/client';
    
const root = createRoot(domElement);
root.render(reactElement);

对于其他两个级别(根的子级),我想在指定的DOM元素中呈现某个组件。

import { createRoot } from 'react-dom/client';

const root = createRoot(childDomElement);
root.render(reactElement);

我收到以下警告:
您正在对之前已传递给createRoot()的容器调用ReactDOMClient.createRoot()。如果要更新现有根,请改为对现有根调用root.render()。
在特定DOM元素中呈现组件的正确方法是什么?

pvcm50d1

pvcm50d11#

这也发生在我身上。对我来说,这是因为DOMContentLoaded回调触发了两次。
我的修复只是确保容器只渲染一次。

let container = null;

document.addEventListener('DOMContentLoaded', function(event) {
  if (!container) {
    container = document.getElementById('root1') as HTMLElement;
    const root = createRoot(container)
    root.render(
      <React.StrictMode>
        <h1>ZOO</h1>
      </React.StrictMode>
    );
  }
});
wz8daaqr

wz8daaqr2#

触发此警告的典型方法是在同一根上多次调用createRoot

ReactDOM.createRoot(document.querySelector("#app"))
  .render(<p>A</p>);
ReactDOM.createRoot(document.querySelector("#app"))
  .render(<p>B</p>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

您可以看到B渲染覆盖了A渲染。
如果要运行两个不同的React应用程序,请使用不同的根:
一个二个一个一个
否则,如果你试图在同一个应用中呈现不同的组件,那么只使用一个根组件呈现一次,然后在根的子树中呈现子组件。大多数页面使用一个React应用程序。
在大多数情况下,createRoot作为整个React应用的一次预先设置,在用户访问页面期间持续存在。呈现条件位于组件树中,您要呈现的元素在组件中指定为JSX。
例如:

const A = () => <p>A</p>;
const B = () => <p>B</p>;
const App = () => <React.Fragment><A /><B /></React.Fragment>;

ReactDOM.createRoot(document.querySelector("#app"))
  .render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

如果出于某种原因,您希望多次渲染到该根目录中,只要限制每个根目录只能调用一次createRoot,您就可以:

const root = ReactDOM.createRoot(document.querySelector("#app"));
root.render(<p>A</p>);

// silly example
setTimeout(() => root.render(<p>B</p>), 2000);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

另一种可能性是您正在寻找一个门户,它可以让您跳出React DOM树并在其他地方呈现组件。尽管如上所述,仍然有一个createRoot和一个render,我们使用门户将组件放在特定的元素中。
例如:

const A = () => <p>A</p>;
const B = () => ReactDOM.createPortal(
  <p>B</p>,
  document.querySelector("#portal")
);
const App = () => <React.Fragment><A /><B /></React.Fragment>;

ReactDOM.createRoot(document.querySelector("#app"))
  .render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
<div id="portal"></div>

门户经常出现在情态动词中。
出于完整性考虑,另一种不常见的触发方式是将Babel包含两次,这可能发生在具有babel: true和import的Stack Snippet中:

ReactDOM.createRoot(document.querySelector("#app"))
  .render(<p>test</p>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

它或多或少与以下内容相同:

<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
<script type="text/babel">
ReactDOM.createRoot(document.querySelector("#app"))
  .render(<p>test</p>);
</script>
k4aesqcs

k4aesqcs3#

你可能从你的入口点文件中导入了一些东西,导致入口点文件不知何故运行了两次。我遇到过同样的问题,通过确保我没有从入口点文件中导入任何东西来解决它。

dbf7pr2w

dbf7pr2w4#

可能还有其他人在使用'react-router-dom'包时遇到了和我一样的错误。
删除<App />(或主组件)组件,并在.render()函数中调用<RouterProvider />组件,如下所示:

ReactDOM.createRoot(document.getElementById('root')).render(<App />)

应改为

ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={mainRouter} />)

RouterProvider Docs

y53ybaqx

y53ybaqx5#

答案就在警告本身。
您正在调用容器上的ReactDOMClient.createRoot(),该容器之前已经传递给createRoot()
在我这里出现警告的根本原因是同一个DOM元素被多次用于创建根。
为了克服这个问题,需要确保createRoot只在
一个DOM元素**上调用一次,之后root.render(reactElement);可以用于更新,而createRoot不应该使用。

相关问题