12

I am using nextjs and mui. I am facing a warning when rendering pages. Here is my code. Please help to solve the issue!!!

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;

Login component is below

    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;

the warning is

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
basarat
  • 261,912
  • 58
  • 460
  • 511
  • Doe`s it happen when moving to a specific page or general? – Blind2k Apr 08 '22 at 06:41
  • You have to setup Material UI for SSR in `_app` and `_document` as in the official example: https://github.com/mui/material-ui/tree/HEAD/examples/nextjs-with-typescript. – juliomalves Apr 10 '22 at 11:45

6 Answers6

11

Case 1

Most likely a Server<>Client out of date issue.

Fix

  • If you are using the development server > Restart it.
  • If you are getting this production > Rebuild + Restart.

Case 2

The components you are using render differently (due to bad coding) on the Server (SSR) vs Client (CSR). This can be silenced by adding suppressHydrationWarning={true} to the offending component.

Case 3

Another case I've seen is that someone has set dangerouslySetInnerHtml with invalid HTML. The fix is to correct the HTML OR silence it as we did in case 2.

basarat
  • 261,912
  • 58
  • 460
  • 511
9

In progress value update from use hook can also causing this problem. To prevent it, just copy the variable value from hook to state from useEffect hook. Here is the example

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>
  );

Explanation: passing value directly from hook to JSX/view may causing inconsistent value inside JSX/view so the the page render can not be consistent as well and there will be different value between value in SSR and client.

Hope it helps.

azwar_akbar
  • 1,451
  • 18
  • 27
4

The genuine issue I had was that LastPass extension was injecting the bloody DIV element into my code. Something like this:

<div data-lastpass-icon-root="true" style="position: relative !important; height: 0px !important; width: 0px !important; float: left !important;"></div>

That obviously caused server and client to have a different node structure. Once exempted localhost from LastPass (which wasn't easy!) the error disappeared.

Greg Wozniak
  • 5,209
  • 3
  • 26
  • 29
  • To exempt localhost from LastPass you can add it as a "Never URL" following [these instructions](https://support.lastpass.com/s/document-item?language=en_US&bundleId=lastpass&topicId=LastPass/Manage_Never_URLs.html&_LANG=enus) and add `localhost/*` as the URL. – bluepanda Jun 02 '23 at 12:54
  • @bluepanda Tried all of those but did not work for me. With any type of regex. Perhaps someone will have more luck. – Greg Wozniak Jun 02 '23 at 16:29
  • You may have luck trying the others mentioned here? https://www.reddit.com/r/Lastpass/comments/xde8wh/comment/ixytf25/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button – bluepanda Jun 06 '23 at 10:22
2

In my case I tried to run localStorage getItem method outside useEffect hook. So probably you can place your async code inside that hook.

Roman T
  • 113
  • 1
  • 9
1

I ran into the same error and it turns out I had a react component outside the body tag in one of my jsx files, specifically layout.tsx.

0

I also got the same issue and resolved it by refreshing the browser

  • Clear Cache
  • Clear Cooke
  • or Try a different browser.
Aravin
  • 6,605
  • 5
  • 42
  • 58