+5

Don't Blindly Trust Error Message Solutions: A Real-Life Example

Mayfest2023

1. Introduction

I've been working with Next.js for about three months in my job. During that time, I encountered an error during development: "Text content does not match server-rendered HTML." Although solving the issue wasn't difficult, the solution I used was different from what I found through Google or what ChatGPT suggested. In this article, I will introduce the general solutions and the one I used, showing that simply searching for error messages might not always lead you to the best solution. Even if you're not familiar with React, you should be able to understand the overall idea.

2. The Code that Caused the Error

Here is a simplified version of the code that caused the error. This component uses Server-Side Rendering (SSR) to render the content. The code is designed to display a comment as-is when it's within 30 characters, and truncate it with "..." if it exceeds 30 characters.

function MyComponent({comment}) {
  const displayedComment = comment.length > 30 
                            ? comment.slice(0, 30) + '...'
                            : comment
  return <div>{displayedComment}</div>
}

3. The Error and General Solutions

The error "Text content does not match server-rendered HTML" occurs when there's a discrepancy between server-side and client-side rendering. Let's look at some common solutions found through Google or provided by ChatGPT.

3.1. Avoid using browser-only libraries or application code

window is only undefined on the server-side, so using it can cause a discrepancy between server and client rendering. One solution is to use useEffect() which is called after rendering.

import { useEffect, useState } from 'react'
function MyComponent() {
  const [color, setColor] = useState('blue')
  useEffect(() => setColor('red'), [])
  return <h1 className={`title ${color}`}>Hello World!</h1>
}

3.2. Use Dynamic Import for components you don't want to render server-side

If you don't want to render a component server-side, you can use the Dynamic Import feature.

import dynamic from 'next/dynamic'

const DynamicHeader = dynamic(() => import('../components/header'), {
  ssr: false,
})

3.3. Correct the HTML structure according to content model rules

HTML tags have parent-child relationship limitations called content models. For example, using a div tag as a child of a p tag is incorrect. You can solve this by replacing the p tag with a div tag.

export const CorrectComponent = () => {
  return (
    <div>
      <div>
        This is correct and should work because a div is really good for this
        task.
      </div>
      <Image src="/vercel.svg" alt="" width="30" height="30" />
    </div>
  )
}

3.4. Add an attribute to ignore the error

You can also use a JSX attribute to suppress the error, as shown in React's official documentation.

export default function App() {
  return (
    <h1 suppressHydrationWarning={true}>
      Current Date: {new Date().toLocaleDateString()}
    </h1>
  );
}

4. The Solution I Adopted

In my case, the error occurred when a comment was truncated right at an emoji or a specific kanji character. These characters are represented by a combination of two special Unicode code points called surrogate pairs. When one of these pairs was cut off by .slice(), the error occurred. While the general solutions mentioned earlier did eliminate the error, they didn't fix the character corruption issue. The best solution was to adjust the character count logic to account for surrogate pairs. I used an array conversion method to handle this.

function MyComponent({comment}) {
  const displayedComment = [...comment].length > 30 
                            ? [...comment].slice(0, 30).join('') + '...'
                            : comment
  return <div>{displayedComment}</div>
}

However, this method still does not solve a case like the one below. If you have a better solution, please let me know.

const str = '👨‍👩‍👧‍👦';
[...str].slice(0, 5);
// Result: [ "👨", "‍", "👩", "‍", "👧" ]

Conclusion

This simple example demonstrates that the best solution for an error is not always the one found by searching the error message. Of course, it's essential to try the solutions you find, but understanding why the error occurs is also crucial. I hope this article helps you in your error-solving journey!

Mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.

Donate mình một ly cafe hoặc 1 cây bút bi để mình có thêm động lực cho ra nhiều bài viết hay và chất lượng hơn trong tương lai nhé. À mà nếu bạn có bất kỳ câu hỏi nào thì đừng ngại comment hoặc liên hệ mình qua: Zalo - 0374226770 hoặc Facebook. Mình xin cảm ơn.

Momo: NGUYỄN ANH TUẤN - 0374226770

TPBank: NGUYỄN ANH TUẤN - 0374226770 (hoặc 01681423001)

image.png


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí