Fix issue with localStorage
mshumayl opened this issue · comments
Commit f18609c
introduced an error that brings the whole site down.
Error: SyntaxError: Unexpected end of JSON input
Culprit:
const [aiResponse, setAiResponse] = useState<responseType>(() => {
const cachedResponse = (typeof window !== "undefined") ? localStorage.getItem("cached_response") : ""; //Because of SSR, need to check if code is running client-side
const parsedCachedResponse = JSON.parse(cachedResponse || "");
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return parsedCachedResponse || defaultResponse;
});
If JSON.parse(cachedResponse || "{}")
, map error occurs:
TypeError: aiResponse.map is not a function
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Source
src\components\PromptInput.tsx (88:23) @ map
86 | </form>
87 | <ul className="flex flex-col items-center w-full">
> 88 | {aiResponse.map(({ surah, verse }) => {
| ^
89 | return ((displayLoader) ?
90 | (<div key={`${surah}_${verse}`} className="animate-ping font-zilla-slab-italic text-xs h-max w-max text-slate-500 my-4 rounded-lg bg-slate-200 py-1 px-2">Thinking...</div>) : (surah !== 0 ) ?
91 | (<VerseCard surah={surah} verse={verse}/
If JSON.parse(cachedResponse || "[{"surah": 0, "verse": 0}, {"surah": 0, "verse": 0}, {"surah": 0, "verse": 0}]")
, hydration error occurs:
Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.
See more info here: https://nextjs.org/docs/messages/react-hydration-error
Can consider JSON.parse(cachedResponse || "{}")
, then check if aiResponse contains any value before rendering. Hopefully this won't cause any hydration issues too.
Doing the above with the following code:
{aiResponse && aiResponse.map && aiResponse.map(({ surah, verse }) => {
return ((displayLoader) ?
(<div key={`${surah}_${verse}`} className="animate-ping font-zilla-slab-italic text-xs h-max w-max text-slate-500 my-4 rounded-lg bg-slate-200 py-1 px-2">Thinking...</div>) : (surah !== 0 ) ?
(<VerseCard surah={surah} verse={verse}/>)
: (<></>)
);}
)}
Yields hydration issues.
Seems to be fixed by dynamically importing VerseCard
with SSR
set to false.
import dynamic from 'next/dynamic';
const VerseCard = dynamic(() => import("./VerseCard"), {ssr: false})
This makes perfect sense as VerseCard
will never need to be rendered on server-side.
To recap, the hydration issue comes from the fact that the number of VerseCard
s rendered on client-side is always more than the number of VerseCard
s rendered on server-side.