most simple way, but it will re-render. It may be related to the scrolling restoration bug when the user return the page if your data is fetched on the client
import {useState, useEffect} from 'react'
export default function Index() {
  const [mounted, setMounted] = useState(false);
  useEffect(() => {
      setMounted(true)
  }, [])
  
  return mounted && <div>Run on client only</div>
}Fixed scroll restoration bugs and re-render problem. but I have to use it with Jotai - state management. You can also use it with other state management.
state.tsx
export const mountedAtom = atom(false)useMounted.tsx
import { useEffect } from "react"
import { useAtom } from "jotai" // 2.2KB gzip
import { mountedAtom } from "state" // import from state.tsx
export default function useMounted() {
  const [mounted, setMounted] = useAtom(mountedAtom)
  useEffect(() => {
    if (!mounted) setMounted(true)
  })
  return mounted
}How you use it:
  const mounted = useMounted()