Auto hide based on state dosen't work in Next, but in pure react app
Unanswered
American Crocodile posted this in #help-forum
American CrocodileOP
I'm trying to write a survey banner that should only be shown if a user has not answered. I first wrote it in a "pure" react app, after transferring it to NextJS the logic for hiding the survey no longer works.
When a user presses the "Yes" or "No" button the survey should immediatly be persistently hidden, but I have to press one of the buttons many times, then wait a few seconds before my pop up hides. Why is this? Is there something next specific I'm not getting?
When a user presses the "Yes" or "No" button the survey should immediatly be persistently hidden, but I have to press one of the buttons many times, then wait a few seconds before my pop up hides. Why is this? Is there something next specific I'm not getting?
import { useState, useEffect } from 'react';
import { Button } from '@ruter-ds-next/button';
import { useTranslation } from 'next-i18next';
const Survey = () => {
const [showSurveyLink, setShowSurveyLink] = useState(true);
const { t } = useTranslation(['common']);
useEffect(() => {
const response = localStorage.getItem('surveyResponse');
if (response) {
setShowSurveyLink(false);
}
}, []);
const handleResponse = (response) => {
localStorage.setItem('surveyResponse', response);
setShowSurveyLink(false);
};
const SurveyBoxTemplate = () => (
<div className="fixed flex flex-col md:bottom-2 md:right-2 bottom-0 right-0 w-full md:w-96 bg-light-fill-quinary-solid bg-fill-quinary-solid dark:bg-dark-fill-primary z-10 p-6 text-dark-background-primary dark:text-dark-ink-primary shadow-raised">
<h2 className="text-body-m-reg pb-6">{t('survey')}</h2>
<div className="flex space-x-4">
<Button
as="a"
href="My amazing form"
target="_blank"
rel="noopener noreferrer"
onClick={() => handleResponse('yes')}
className="w-1/2 text-center"
>
{t('yes')}
</Button>
<Button
skin="SECONDARY"
onClick={() => handleResponse('no')}
className="w-1/2"
>
{t('no')}
</Button>
</div>
</div>
);
return <>{showSurveyLink && <SurveyBoxTemplate />}</>;
};
export default Survey;
13 Replies
try adding a mounted state
import { useState, useEffect } from 'react';
import { Button } from '@ruter-ds-next/button';
import { useTranslation } from 'next-i18next';
const Survey = () => {
const [showSurveyLink, setShowSurveyLink] = useState(true);
const { t } = useTranslation(['common']);
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
const response = localStorage.getItem('surveyResponse');
if (response) {
setShowSurveyLink(false);
}
}, []);
const handleResponse = (response) => {
localStorage.setItem('surveyResponse', response);
setShowSurveyLink(false);
};
const SurveyBoxTemplate = () => (
<div className="fixed flex flex-col md:bottom-2 md:right-2 bottom-0 right-0 w-full md:w-96 bg-light-fill-quinary-solid bg-fill-quinary-solid dark:bg-dark-fill-primary z-10 p-6 text-dark-background-primary dark:text-dark-ink-primary shadow-raised">
<h2 className="text-body-m-reg pb-6">{t('survey')}</h2>
<div className="flex space-x-4">
<Button
as="a"
href="My amazing form"
target="_blank"
rel="noopener noreferrer"
onClick={() => handleResponse('yes')}
className="w-1/2 text-center"
>
{t('yes')}
</Button>
<Button
skin="SECONDARY"
onClick={() => handleResponse('no')}
className="w-1/2"
>
{t('no')}
</Button>
</div>
</div>
);
return <>{mounted && showSurveyLink && <SurveyBoxTemplate />}</>;
};
export default Survey;
American CrocodileOP
Thanks for the suggestion @Ray ! I tried mounted state earlier, and updated the code to your suggestion now. but the same issue persist, I have to press the buttons multiple times and wait for anything to happen
<Button
href="My amazing form"
target="_blank"
rel="noopener noreferrer"
onClick={() => handleResponse('yes')}
className="w-1/2 text-center"
>
{t('yes')}
</Button>
try removing the
as
propsAmerican CrocodileOP
same issue happens with the "No" button that is not as='a'
how about turning <Button /> to <button> ?
American CrocodileOP
Tried it now, same issue persists. <Button> renders a pure <button> (unless it has as-prop) with some styling
could you record a video?
American CrocodileOP
sure, give me a few seconds to figure out how to record a video first 🙂
cmd + shift + 5 on mac
win + alt + r on window
win + alt + r on window
American CrocodileOP
try this
import { flushSync } from "react-dom";
const handleResponse = (response) => {
localStorage.setItem("surveyResponse", response);
flushSync(() => {
setShowSurveyLink(false);
});
};
American CrocodileOP
have some meetings now, thanks will try this as soon as I can 🙂
the top of the react docs looked a bit scary
"Using flushSync is uncommon and can hurt the performance of your app."
the top of the react docs looked a bit scary
"Using flushSync is uncommon and can hurt the performance of your app."
I think its fine for this use case if it works