error일지

[Next] Warning: Prop `style` did not match. Server: "null" Client: "color:"

rachel_13 2023. 5. 5. 14:44

Link Component에 조건부 인라인 스타일링(color 값 주기)을 해줬을 때 나타는 오류이다.

Server 측에서 초기 렌더링 될 때 color 속성이 없어서 (null로 설정되어있기 때문) Client 측과 일치하지 않아 발생하는 문제.

→ Hydration Error 라고 console에서 알려주고 있다.

https://nextjs.org/docs/messages/react-hydration-error

 

react-hydration-error | Next.js

Text content does not match server-rendered HTML While rendering your application, there was a difference between the React tree that was pre-rendered (SSR/SSG) and the React tree that rendered during the first render in the Browser. The first render is ca

nextjs.org

대충 요약해보자면,

 

발생 원인

  • 어플리케이션을 렌더링하는 동안 pre-rendering된 React 트리(Hydration)와 브라우저의 첫번째 렌더링 중에 rendering된 React 트리 간의 차이로 발생하였다. 
  • 일반적으로 이 문제는 특정 라이브러리 또는 특정 소스코드에서 pre-rendering과 브라우저 rendering 간에 다를 수 있는 항목들에 의존할 경우 발생하며, 아마도 필자의 경우 useRouter를 이용해서 pathname을 가져올 때 한번 더 렌더링되어서 component의 렌더링 과정에 차이가 발생한 것으로 추측된다.

 

어떻게 고쳐?

  • useEffect hook 사용하기 - useEffect 는 최초에 컴포넌트들이 그려지고 난 후에 호출되기 때문에 클라이언트 사이드에서의 동작이 보장되어 있음.
  • (수정전)
import { useRouter } from "next/router";
import Link from "next/link";
import styles from ".//NavBar.module.css";

export default function NavBar() {
  const router = useRouter();
  return (
    <nav className={styles.nav}>
      <Link href="/" style={{ color: router.pathname === "/" ? "blue" : "" }}>
        Home
      </Link>
      <Link
        href="/about"
        style={{ color: router.pathname === "/about" ? "blue" : "" }}
      >
        About
      </Link>
    </nav>
  );
}
  • (수정후)
import { useRouter } from "next/router";
import Link from "next/link";
import styles from ".//NavBar.module.css";
import { useEffect } from "react";
import { useState } from "react";

export default function NavBar() {
  const [color, setColor] = useState("black");
  const [color2, setColor2] = useState("black");
  const router = useRouter();

  useEffect(() => {
    if (router.pathname === "/") {
      setColor("blue");
      console.log("1");
    }
  }, [router.pathname]);

  useEffect(() => {
    if (router.pathname === "/about") {
      setColor2("blue");
      console.log("2");
    }
  }, [router.pathname]);

  return (
    <nav className={styles.nav}>
      <Link href="/" style={{ color: color }}>
        Home
      </Link>
      <Link href="/about" style={{ color: color2 }}>
        About
      </Link>
    </nav>
  );
}

그런데 굳이 저렇게 effect 훅을 쓰지 않아도, inline style을 안쓰고 className에 조건 주면 해결됨.