reactjs - i NEXTJS Advarsel: Forventet at server-HTML skulle inneholde en matchende <div> i <div>


Jeg bruker nextjs og mui. Jeg får en advarsel når jeg renderer sider. Her er koden min. Vennligst hjelp meg med å løse problemet!!!

import "../styles/globals.scss";
import { AppProps } from "next/app";
import useGetAuthentication from "../hooks/useGetAuthentication";
import States from "../interfaces/states";
import STATUS from "../constants/status";
import { CssBaseline } from "@mui/material";
import { ThemeProvider } from "@mui/material/styles";
import theme from "../styles/theme";
import Layout from "../layouts/Layout";
import Head from "next/head";
import * as React from "react";
import Login from "../components/Login";
import { Box } from "@mui/material";

interface MyAppProps extends AppProps {
  emotionCache?: EmotionCache;
}

const checkStatusCode = (statusCode: number): boolean => {
  return statusCode === STATUS.NOT_FOUND || statusCode === STATUS.INTERNAL_SERVER_ERROR;
};

function App({ Component, pageProps }: AppProps) {
  const { states } = pageProps;
  const { statusCode } = pageProps;
  const { isAuthorized } = useGetAuthentication(states as States);

  console.log("App -> Component", Component);
  console.log("App -> pageProps", pageProps);
  console.log("App -> states", states);
  console.log("App -> statusCode", statusCode);
  const drawerWidth: number = 240;
  if (!checkStatusCode(statusCode) && !isAuthorized)
    return (
      <Box
        component="main"
        sx={{
          flexGrow: 1,
          p: 3,
          width: { lg: "230px", sm: `calc(100% - ${drawerWidth}px)` }
        }}
      >
        <Login />
      </Box>
    );

  return (
    <>
      <Head>
        <meta name="viewport" content="initial-scale=1, width=device-width" />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <Layout>
          <Component {...pageProps} />
        </Layout>
      </ThemeProvider>
    </>
  );
}

export default App;

Innloggingskomponent er nedenfor

    import React, { useEffect } from "react";
import authenticationStore from "../../stores/persistences/authenticationStore";
import TestHttp from "../../httpModules/testHttp";
import STATUS from "../../constants/status";
import RequestSignIn from "../../interfaces/test/requestSignIn";
import styles from "./login.module.scss";
import { Alert, FormControlLabel, Grid, Paper, TextField, Typography, Stack, Button, Checkbox } from "@mui/material";
import Image from "next/image";
import useLoginInputs from "../../hooks/useLoginInputs";
import LocalStorageHandler from "../../utils/localStorageHandler";
import RememberId from "../../interfaces/rememberId";
import ERROR_MESSAGE from "../../constants/errorMessage";
import LOGIN_INFO from "../../constants/loginInfo";

const Login: React.FC = () => {
  const localStorageHandler = new LocalStorageHandler<RememberId>();
  const authorize = authenticationStore((state) => state.authorize);
  const testHttp = new TestHttp();
  const { inputs, setInputs, isRememberChecked, isError, setIsError, isIdEmpty, setIsIdEmpty, isPasswordEmpty, setIsPasswordEmpty, inputsHandler, checkboxHandler } = useLoginInputs([
    "id",
    "password"
  ]);

  const { id, password } = inputs;

  const onLoginHandler = async (): Promise<void> => {
    if (isIdEmpty) {
      return setIsError(ERROR_MESSAGE.ID_EMPTY);
    }
    if (isPasswordEmpty) {
      return setIsError(ERROR_MESSAGE.PASSWORD_EMPTY);
    }
    const signInInfo: RequestSignIn = { id, password };
    const { statusCode, jsonResult } = await testHttp.signIn(false, signInInfo);

    /*
     *   인증 실패 (아이디, 비밀번호 일치 하지 않는 경우 등) 발생 시 코드 작성
     */

    if (statusCode !== STATUS.OK) {
      setIsError(true);
      return;
    }
    const { userInfo, tokenInfo } = jsonResult;
    authorize(statusCode, userInfo, tokenInfo);
    if (!isRememberChecked) return localStorageHandler.removeLocalStorageData(LOGIN_INFO.REMEMBER_ID);
    localStorageHandler.setLocalStorageData("rememberId", {
      id
    });
  };

  useEffect(() => {
    console.log("하이");
    setIsIdEmpty(id.length <= 0);
    setIsPasswordEmpty(password.length <= 0);
    setIsError(null);
  }, [id, password]);

  console.log("id", id);
  console.log("password", password);
  return (
    <Grid>
      <Paper elevation={10} className={styles.container}>
        <Grid align={"center"}>
          <div className={styles.logo}>
            <Image src={"/images/logo.svg"} width={"200px"} height={"80px"} alt={"logo"} />
            <Typography variant={"h6"}>관리자</Typography>
          </div>
        </Grid>
        <Stack spacing={1} justifyContent={"center"} alignItems={"center"} className={styles["login-container"]}>
          <TextField name={"id"} placeholder={"아이디를 입력해주세요."} required value={id} type={"text"} className={styles["login-input"]} onChange={inputsHandler} />
          <TextField name={"password"} placeholder={"비밀번호를 입력하세요."} required value={password} type={"password"} className={styles["login-input"]} onChange={inputsHandler} />
        </Stack>
        <Stack>
          <FormControlLabel control={<Checkbox checked={isRememberChecked} />} label={"아이디 저장"} className={styles.checkbox} onChange={checkboxHandler} />
        </Stack>
        <Stack justifyContent={"center"} alignItems={"center"}>
          <Button type={"submit"} color={"primary"} variant={"contained"} className={styles["login-button"]} size={"large"} onClick={onLoginHandler}>
            로그인
          </Button>
        </Stack>
        <Stack justifyContent={"center"} alignItems={"center"} className={styles["error-message"]}>
          <div>
            {isError && (
              <Alert severity={"error"}>
                <strong>{isError}</strong>
              </Alert>
            )}
          </div>
        </Stack>
      </Paper>
    </Grid>
  );
};

export default Login;

advarselen er

Warning: Expected server HTML to contain a matching <div> in <div>.
    at div
    at eval (webpack-internal:///./node_modules/@emotion/react/dist/emotion-element-cbed451f.browser.esm.js:57:66)
    at Box (webpack-internal:///./node_modules/@mui/system/esm/createBox.js:36:72)
    at Layout (webpack-internal:///./layouts/Layout/index.tsx:16:26)
    at InnerThemeProvider (webpack-internal:///./node_modules/@mui/system/esm/ThemeProvider/ThemeProvider.js:21:70)
    at ThemeProvider (webpack-internal:///./node_modules/@mui/private-theming/ThemeProvider/ThemeProvider.js:47:5)
    at ThemeProvider (webpack-internal:///./node_modules/@mui/system/esm/ThemeProvider/ThemeProvider.js:41:5)
    at App (webpack-internal:///./pages/_app.tsx:61:27)
    at ErrorBoundary (webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/client.js:8:20638)
    at ReactDevOverlay (webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/client.js:8:23179)
    at Container (webpack-internal:///./node_modules/next/dist/client/index.js:323:9)
    at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:820:26)
    at Root (webpack-internal:///./node_modules/next/dist/client/index.js:944:27)
window.console.error @ next-dev.js?3515:25

Svar #1

Oppdatering av verdien underveis fra use-hook kan også forårsake dette problemet. For å forhindre det, kopier bare variabelverdien fra hooken til state fra useEffect-hooken. Her er eksemplet

import { useAccount } from "wagmi";

...

  const { address, isConnected, isConnecting } = useAccount();
  // the value of these variable above are changed dynamically
  
  const [connectionStat, setConnectionStat] = useState();
  const [addr, setAddr] = useState();

  // copy the value to state here
  useEffect(() => {
    setConnectionStat(isConnected);
    setAddr(address);
  }, [address, isConnected])

  // then now we can display the value properly

  return (
    <div>
     <p>Connection status :  {connectionStat}</p>
     <p>Connected to      :  {addr}</p>
      ....
    </div>
  );

Forklaring: Å sende verdi direkte fra hook til JSX/view kan forårsake inkonsistente verdier inne i JSX/view, så sidegjengivelsen kan heller ikke være konsistent, og det vil være forskjellige verdier mellom verdien i SSR og klient.

Håper det hjelper.

Svar #2

Sak 1

Sannsynligvis et Server<>Client problem med utdatert versjon.

Fiks

  • Hvis du bruker utviklingsserveren > start den på nytt.
  • Hvis du får denne produksjonen > Bygg på nytt + Start på nytt.

Sak 2

Komponentene du bruker gjengis forskjellig (på grunn av dårlig koding) på Serveren (SSR) vs Klienten (CSR). Dette kan dempes ved å legge til suppressHydrationWarning={true} på den aktuelle komponenten.

Sak 3

Et annet tilfelle jeg har sett er at noen har satt dangerouslySetInnerHtml med ugyldig HTML. Løsningen er å rette opp i HTML-en ELLER å dempe det slik vi gjorde i tilfelle 2.

Relaterte artikler