next.js에서 랜덤 수를 사용할 때 빠진 노트

next.js에'업데이트할 때마다 랜덤으로 UUID를 생성합니다'라는 페이지가 적혀 있을 때 적합한 노트입니다.

현상.


예를 들어 이런 상황의 코드를 쓴 경우.
import { v4 } from "uuid" // uuid.v4()はUUIDをランダム生成する関数

export default function RandomComponent ()  {
  const [uuid, setUuid] = useState(v4())
  return <div>
    uuid1: {uuid1} 
  </div>
}
이 경우 SSR에서 UUID를 한 번 생성한 다음 클라이언트에서 UUID를 다시 보냅니다.
이로 인해 오류가 발생했고, 이런 오류가 발생했다.
Warning: Text content did not match. 
Server: "c5d1f100-b9a1-4ee5-9f53-9a659265872e" 
Client: "14a70ba1-546d-49e9-9f8b-0f2938969f87"
오류가 발생했지만 클라이언트에서 두 번째로 발표된 UID를 출력합니다.
아직까지는 예상하지 못했지만 이 랜덤 수를 속성으로 처리하면 예상치 못한 일이 발생할 수 있다.
import { v4 } from "uuid" // uuid.v4()はUUIDをランダム生成する関数

export default function RandomComponent ()  {
  const [uuid, setUuid] = useState(v4())
  return <div>
    <a href={uuid1}> {/* ①この値はレンダリング後にも更新されない */}
      uuid: {uuid} {/* ②この値はレンダリング後にも更新される */}
    </a>
  </div>
}
그리고 dev가 아닌 서버에서 실행하면 ②측면의 text 노드 부분은 리셋할 때마다 무작위로 변경되지만 ①의 DOM 속성으로 설정된 측은 리셋해도 업데이트되지 않습니다.
아마 Automatic Static Optimization 효과가 있을 거예요.
따라서 다음과 같은 경우getServerSideProps가 있으면 비활성화되고 다시 불러올 때마다 업데이트됩니다.
// 下記のように該当コンポーネントを利用するページでgetServerSidePropsがあると無効になる
export const getServerSideProps = () => ( {
  props: {}
})
워닝이 원래 나왔는데 그래도 속성만 업데이트되지 않는 건 좀 부자연스럽고 알아채기 어려운 부분이라 해결 방법을 정리했습니다.

해결책


1. 넥스트/dynamic를 이용한 해결 방법


아마도 이 방법은 가장 정면으로 공격하는 것일 뿐만 아니라 원가도 매우 적을 것이다.{ssr: false}에서dynamic import를 통해 SSR을 하지 않기 때문에 해결되었습니다.
단, 처리를 클라이언트에 양도하는 방법이기 때문에 SSR의 은혜를 받을 수 없습니다
const DynamicComponent = dynamic(() => import("../components/dynamic"), { ssr: false })

export default function Page ()  {
  return <DynamicComponent />
}

2. getServer SideProops의 해결 방법 활용


서버 쪽에서만 무작위 수를 정하면 getServer SideProops를 사용할 수 있습니다.
export default function Page({ serverSideValue }) {
  return <div>
    <a href={`${serverSideValue}`}>
      serverSideValue: {serverSideValue}
    </a>
  </div>
}

export const getServerSideProps = () => {
  return {
    props: {
      serverSideValue: v4()
    }
  }
}

3. useEffect의 해결 방법(사용처 선택) 활용


다이내믹 import 같은 열악한 버전도 있지만 useEffect를 이용한 해결 방법도 있다
const EffectComponent = () => {
  const [uuid, setUuid] = useState(null)
  useEffect(() => {
    setUuid(v4())
  }, [])
  
  if (!uuid) {
    return null
  }
  return <div>
    <a href={uuid}>
      Effect Component: {uuid}
    </a>
  </div>
}
그렇다면 SSR 시null에 되돌아오고 클라이언트에서useEffect에서 UUUID를 결정합니다.

좋은 웹페이지 즐겨찾기