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.
