Я пробовал next.js и столкнулся с ситуацией, когда мне нужен клиентский компонент, то есть компонент загрузчика, который должен отображаться в серверном компоненте. Но как только я включаю компонент Loader, он выдает ошибку, в которой говорится:
Неперехваченное исключение DOMException: не удалось выполнить «appendChild» на «Узле»: только разрешен один элемент в документе.
вот мой компонент загрузчика
"use client";
import React from "react";
import { useSelector } from "react-redux";
import { RootState } from "@/lib/reducers";
const Loader = () => {
const loading = useSelector((state: RootState) => state.loading);
return <div>{loading ? "Loader" : null}</div>;
};
export default Loader;
а вот серверный компонент, который также является моим корневым макетом, который отображает Loader
import "./globals.css";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import Loader from "@/components/Loader";
import { Providers } from "@/lib/providers";
import SessionWrapper from "../components/SessionWrapper";
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<Providers>
<Loader /> //this throws error when used
<SessionWrapper>
<html lang = "en">
<body className = {`${inter.className} min-h-screen`}>{children}</body>
</html>
</SessionWrapper>
</Providers>
);
}
вот компонент поставщика, который является клиентским компонентом и оболочкой всего макета
'use client';
import { Provider } from "react-redux";
export function Providers({ children }: { children: React.ReactNode }) {
return <Provider store = {store}>{children}</Provider>;
}
Есть ли способ отобразить здесь клиентский компонент, потому что, если я использую этот компонент загрузчика в любом другом серверном компоненте, скажем, -pages/dashboard/layout.tsx, он работает нормально.
@Arashjahanbakhshan обновил сообщение, включая код для компонента поставщика, он принимает дочерние элементы, поэтому я думаю, количество элементов не имеет значения.
Я до сих пор не знаю, откуда взялся Provider :) что за библиотека?
это из реакции-редукса, который импортируется как импорт {Провайдер} из "реагировать-редукс";
ознакомьтесь с этой документацией по использованию Redux с NextJS 14. Возможно, это решит вашу проблему (redux.js.org/usage/nextjs)





Я приведу вам пример, чтобы продемонстрировать, что именно вы делаете, а затем объясню дальше.
Если бы я спросил вас: имеет ли смысл приведенный ниже код в обычном HTML?
<div>I'm living besides html tag!</div>
<html lang = "en">
<body>Hello world</body>
</html>
Точно! Нет, это не так. У вас не может быть div или любого другого элемента, кроме html. Это плохой и нетрадиционный способ написания HTML. Тем не менее, это будет работать благодаря возможностям современных веб-браузеров, которые могут анализировать HTML и отображать контент, даже если HTML не идеально структурирован.
Однако в Next.js существуют более строгие правила, которые могут привести к сбою вашего приложения из-за таких проблем. Теперь, если вам интересно, где я допустил такую ошибку? проверьте приведенный ниже код.
<Providers>
<Loader />
<SessionWrapper>
<html lang = "en">
<body className = {`${inter.className} min-h-screen`}>{children}</body>
</html>
</SessionWrapper>
</Providers>
// The above will be translated to something like:
<div>Loader...</div>
<html lang = "en">
<body class = "YOUR_ClASSES">{/* YOUR CONTENT */}</body>
</html>
и именно поэтому в других компонентах он работает правильно, потому что он находится внутри body.
Одним из решений может быть предоставление двух загрузчиков: одного для корневого компонента, а другого для остальных компонентов.
Загрузчик корневого компонента может выглядеть так:
"use client";
import { RootState } from "@/lib/reducers";
import React from "react";
import { useSelector } from "react-redux";
const Loader = () => {
const loading = useSelector((state: RootState) => state.loading);
return (
<html lang = "en">
<body>
<div>{loading ? "Loader" : null}</div>
</body>
</html>
);
};
export default Loader;
Каким последним провайдером вы пользовались? возможно, он ожидает внутри себя только 1 элемент. попробуйте поставить
LoaderиSessionWrapperво фрагмент реакции:<>...</>илиdiv