Mengatasi Minified React Error #425 #418 #423
Wed. Apr 10th, 2024 11:50 PM4 mins read
Mengatasi Minified React Error #425 #418 #423
Source: Bing Image Creator - React JS Error

Minified React Error adalah error yang biasanya terjadi pada website berbasis Rendering di server seperti SSR, SSG, DSG, atau ISR pada framework kayak GatsbyJS, React, NextJS, dan sejenisnya. Biasanya terdapat 3 error: Minified React error #425, Minified React error #418, dan Minified React error #423. Ketiga error tersebut root cause-nya umumnya sama. Inti dari permasalahan ketiganya adalah terjadi perbedaan antara konten hasil build dari server dengan konten awal yang dimuat di browser.

Hydration

Sebelum kita telaah lebih jauh solusinya, kita perlu pahami dulu masalahnya, yaitu Hydration. Hydration adalah proses transisi dari halaman yang tadinya statis menjadi interaktif. Pada saat browser pertama kali load sebuah halaman berbasis Rendering di server, sebenarnya server melakukan generate konten halamannya dengan mengeksekusi JS di server dan menghasilkan output halaman statis berupa HTML & CSS doang. Jadi, saat browser pertama kali menerima response, ga ada JS dan belum bisa mengeksekusi hal-hal terkait JS. Lalu server akan mengirimkan JS secara terpisah dan barulah browser mengeksekusi JS yang diterima hingga website tersebut menjadi interaktif. Itulah yang disebut dengan Hydration. Makanya website tersebut loading awalnya jadi cukup cepat dan SEO-nya cenderung bagus karena ga ada JS di awal.

Problem

Masalahnya, kalau logic saat build/render di server dan logic saat Hydration di browser hasilnya beda, maka akan error. Perbedaan itu terjadi karena ada logic yang hasilnya dinamis, seperti tampilan waktu, hasil dari function Math.Random(), atau hal lainnya. Untuk memastikannya, cek tools network di browser, lalu hard refresh halaman tersebut, dan lihat response HTML di paling atas. Kemudian bandingkan dengan tampilan yang muncul di web dan cari perbedaannya. Di kasus yang gw hadapi, masalahnya di bagian tanggal. Di server gw menggunakan UTC. Sedangkan timezone browser gw dan data tanggal yang gw simpan adalah Asia/Jakarta (+07:00). Jadinya saat pertama load atau hard refresh, muncul waktu dalam zona UTC sesuai hasil generate di server, lalu sepersekian detik kemudian terjadi “quick flash” dan berubah menjadi waktu Asia/Jakarta sesuai waktu browser. Ketidaksamaan hasil tampilan dari server dengan browser itu yang mengakibatkan error. Kalau run di localhost biasanya ga kejadian karena timezone di server local dengan browser harusnya sama.

Timezone Solution

Kalau kasusnya spesifik terkait timezone seperti yang gw alami, bisa dengan mendefinisikan timezone sebelum digunakan. Contoh kasusnya ketika menggunakan date-fns untuk mengkonversi tanggal dengan timezone berupa String menjadi format tertentu seperti ini:

import { format } from "date-fns";

<span className="page-info">
  {`date = ${format("2023-04-18T03:00+07:00", "yyyy-MM-dd hh:mm a")}`}
</span>

Gw menggunakan String dengan format ISO “2023-04-18T03:00+07:00”, yaitu tanggal 18 April 2023 jam 03:00 dengan offset +07:00, alias zona waktu Jakarta yang akan dikonversi menjadi format “2023-04-18 03:00 AM”. Oleh library date-fns, tanggal tersebut akan di-convert baik di server maupun di browser nanti. Hasilnya tentu saja bakal berbeda karena servernya belum tentu timezone-nya sama dengan timezone browser yang mengakses halaman tersebut. Inilah sumber masalahnya.

Untuk mengakalinya, kita perlu bikin function untuk convert tanggalnya dengan locale string beserta option timezone yang ingin dijadikan patokan seperti berikut agar apapun timezonenya nanti di browser maupun di server hasilnya jadi selaras dan ga error.

import { format } from "date-fns";

function formatToPattern(dateArgString, datePattern) {
  const date = new Date(dateArgString);
  const zonedDate = date.toLocaleString("en-US", { timeZone: "Asia/Jakarta" });
  return format(zonedDate, datePattern);
}

Pas render nanti yang kita panggil adalah function yang kita bikin tadi.

<span className="page-info">
  {`date = ${formatToPattern("2023-04-18T03:00+07:00", "yyyy-MM-dd hh:mm a")}`}
</span>

Setelah melakukan hal di atas, silakan commit, deploy, dan liat langsung hasilnya di server😎.

Luxon Solution

Salah satu alternatif lainnya adalah dengan menggunakan library Luxon yang ga menggunakan native Date dari JS, melainkan tipe data tanggal sendiri, yaitu DateTime. Fiturnya juga lengkap termasuk immutable type, relative time, dan zona waktu. Dengan Luxon kita ga perlu bikin logic sendiri karena ada fitur set zona waktu. Code-nya jadi seperti ini:

import { DateTime } from "luxon";

<span className="page-info">
  {`date = ${DateTime.fromISO("2023-04-18T03:00+07:00").setZone("Asia/Jakarta").toFormat("yyyy-MM-dd hh:mm a")}`}
</span>

Wrapper Component Solution

Untuk kasus lainnya bisa diakali dengan menambahkan logic untuk menampilkan placeholder yang kita inginkan saat pertama kali load. Sehingga baik di sisi server maupun browser saat pertama kali load kontennya berupa placeholder yang sama dan terhindar dari error. Konten aslinya akan di-load belakangan di sisi browser saja setelah Hydration. Contohnya saat generate Math.Random(), new Date(), Date.now(), atau sejenisnya yang harusnya di-generate di browser saja karena setiap dieksekusi hasilnya pasti akan selalu berbeda. Di kasus gw contohnya adalah saat menampilkan logic updated date dengan value kalimat jarak waktu antara waktu terakhir perubahan dengan waktu browser saat ini menggunakan date-fns.

import { formatDistance } from "date-fns";

<span className="page-info">
  {`updated ${formatDistance("2023-04-18T03:00+07:00", new Date(), { addSuffix: true })}`}
</span>

Code di atas akan error karena di function tersebut kita melakukan generate waktu saat ini menggunakan new Date() yang hasilnya tentu akan beda tiap milliseconds dan dapat membuat hasil eksekusi di server dan browser berbeda.

Solusinya kita akan membuat component khusus yaitu ClientSide sebagai container untuk membungkus bagian yang hanya akan di-generate di sisi browser aja. Kita akan menggunakan useState() & useEffect() untuk mengecek statenya saat pertama kali load di browser lewat variable onClient. Kita set initial valuenya jadi false. Kita akan menampilkan placeholder “…” saat statenya masih false waktu dieksekusi di server dan sebelum Hydration di browser. Lalu setelah Hydration di browser state-nya akan berganti menjadi true dan menampilkan konten sesuai yang kita inginkan. Code-nya seperti berikut:

function ClientSide({ children }) {
  const [onClient, setOnClient] = useState(false);
  useEffect(() => {
    setOnClient(true);
  }, []);
  if (onClient) {
    return <>{children}</>;
  }
  return <></>;
}

Kemudian kita ganti code di bagian render-nya dengan membungkus bagian yang hanya ingin di-generate di sisi browser saja menggunakan component ClientSide tadi seperti berikut:

import { formatDistance } from "date-fns";

<ClientSide>
  <span className="page-info">
    {`updated ${formatDistance("2023-04-18T03:00+07:00", new Date(), { addSuffix: true })}`}
  </span>
</ClientSide>

Karakter “…” akan muncul saat render di server maupun saat Hydration di browser. Setelah proses Hydration, browser akan generate konten yang ada di dalam ClientSide. Sekarang errornya sudah tidak ada lagi di console.log dan konten yang muncul sesuai dengan yang diinginkan😎. Kita juga bisa reuse component itu di berbagai code yang hasil rendernya dinamis, jadi ga perlu bikin lagi tiap kasus.

© 2025 · Ferry Suhandri