היום למדתי: פקודת browser ב next.js
כשלמדתי next.js לקח לי זמן להבין שכשאני כותב use client בתחילת קובץ הכוונה שלהם היא שהקוד ירוץ גם ב client וגם ב server, ולא רק ב client כמו שאולי היה אפשר להבין מהשם.
למעשה בעבודה עם ריאקט ו next הרצת קוד רק בדפדפן תמיד היתה קצת מסורבלת. הנה מה שקלוד הדפיס כשביקשתי ממנו לכתוב קומפוננטה ל next שקוראת ערך ששמור ב local storage ומדפיסה אותו:
'use client';
import { useEffect, useState } from 'react';
export default function StoredValue({ storageKey = 'username', fallback = 'Not set' }) {
// null means "haven't read storage yet" — distinct from an empty stored value
const [value, setValue] = useState(null);
useEffect(() => {
try {
setValue(localStorage.getItem(storageKey) ?? fallback);
} catch {
// Storage can throw in private mode or when disabled
setValue(fallback);
}
}, [storageKey, fallback]);
if (value === null) return <p>Loading…</p>;
return <p>{value}</p>;
}
בשביל לקרוא מ local storage ריאקט היה צריך להחביא את הקוד שקורא מקוד צד השרת שיריץ אותו, כי על השרת ה local storage אולי לא זמין ובטוח מכיל ערכים אחרים.
לאחרונה next הוסיפו מנגנון חמוד בשם browser: https://react.dev/reference/react-dom/browser
המטרה שלו לאפשר לסמן קוד שירוץ רק בדפדפן ולא על השרת. כן, כאילו הוא מוסתר באפקט רק בלי כל הטקס. הנה הגרסה המודרנית של אותו קוד:
'use client';
import { use, useState } from 'react';
import { browser } from 'react-dom';
export default function StoredValue({ storageKey = 'username', fallback = 'Not set' }) {
use(browser('The value is stored in localStorage.'));
const [value] = useState(() => localStorage.getItem(storageKey) ?? fallback);
return <p>{value}</p>;
}
המלכודת היחידה בעדכון היא לכתוב את הקומפוננטה רק בתוך Suspense Boundary כלומר:
import { Suspense } from 'react';
import StoredValue from './StoredValue';
export default function Page() {
return (
<Suspense fallback={<p>Loading…</p>}>
<StoredValue />
</Suspense>
);
}
אבל בטח יש לכם אחד כזה ביישום כבר בשביל כל הפיצ'רים האחרים שבנויים עליו.