Thông thường phần nội dung cửa website chúng ta sẽ sử dụng dangerouslySetInnerHTML để hiển thị, nhưng khi sử dụng dangerouslySetInnerHTML thì không thể nào sử dụng thẻ Image của Next/Image, dẫn đến tình trạng hình ảnh trong phần bài viết chưa được tối ưu.
Thư viện html-react-parser sẽ giúp bạn thay thể thẻ <img> thông thường thàng <Image> của Nextjs một cách dễ dàng.
npm install html-react-parser --save
//hoặc
yarn add html-react-parser
// ở dưới đây là đoạn code tóm tắt cách sử dụng
'use client';
import parse from 'html-react-parser'; //<-- thêm thư viện
import Image from 'next/image';
import React, { useEffect } from 'react';
type ImageType = {
src: string;
};
const listImage: ImageType[] = [];
let indexImage = 0;
//xử lý thay thẻ img thành thẻ Image của Nextjs
const replaceImages = (node: Node) => {
if (node.name === 'p' && node.children && node.children[0].name === 'img') {
const { src, alt, ...rest } = node.children[0].attribs as Record<
string,
string
>;
listImage.push({ src });
return (
<p className='hinhanh'>
<Image
src={src}
alt={alt}
loading={indexImage === 0 ? 'eager' : 'lazy'} // ở đây thì tấm ảnh đầu tiên chúng ta không nên dùng lazy nhé, còn những tấm phía sau thì dùng lazy
width={600} // thay đổi kích thước phù hợp với yêu cầu của bạn
height={400} // thay đổi kích thước phù hợp với yêu cầu của bạn
placeholder='blur' //cái này để hiển thị ảnh mờ trước khi ảnh load xong, cái này để google pagespeed tối ưu
blurDataURL={src + '&quality=1'} //cái này để hiển thị ảnh mờ trước khi ảnh load xong, cái này để google pagespeed tối ưu
{...rest}
className='max-w-xl w-full h-auto'
/>
</p>
);
}
};
export default function NoiDungBaiViet({ noidungbaiviet}: { noidungbaiviet: string;}) {
return (
<div className='noidung p-1 border-t text-base'>
{parse(noidungbaiviet,
{
replace(domNode) {
return replaceImages(domNode);
},
}
)}
</div>
);
}
Ở đoạn code trên các bạn có thể thấy, mình đã thay dangerouslySetInnerHTML thành thẻ parse của html-react-parser và sử dụng thêm một hàm replace với tham số truyền vào là một domNode, xong sẽ xử lý ở hàm replaceImages.
Hàm replaceImages sẽ kiểm tra xem nếu thẻ hiện tại là thẻ p và có thẻ con là img thì nó sẽ tiến hành thay đổi thành thẻ Image của nextjs. Vì sao ở đây mình không check thẻ img thôi mà phải kiểm tra luôn thẻ p, bởi vì ở đây mình muốn hình ảnh cửa mình nằm giữa bài viết bằng cách thêm thẻ class=hinhanh vào thẻ p, việc này sẽ giúp khi bài viết xuất hiện thì ảnh cửa mình sẽ tự động nằm giữa bài viết.
//Đoạn css để hình ảnh nằm giữa bài viết
.hinhanh {
display: flex;
justify-content: center; /* căn giữa theo chiều ngang */
align-items: center; /* căn giữa theo chiều dọc */
}
Lưu ý là: khi sử dụng html-react-parser có thể tăng thời gian Total Blocking Time
Đây là cách mà mình sử dụng để tối ưu hoá hiệu năng của nextjs, nếu bạn có cách nào hay hơn thì hãy bình luận để mình biết thêm nhé.