Next.js Discord

Discord Forum

Auto hide based on state dosen't work in Next, but in pure react app

Unanswered
American Crocodile posted this in #help-forum
Open in Discord
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?

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

@American Crocodile 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? js 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;
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
@American Crocodile Thanks for the suggestion <@743561772069421169> ! 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 props
American CrocodileOP
same issue happens with the "No" button that is not as='a'
@American Crocodile 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
American CrocodileOP
sure, give me a few seconds to figure out how to record a video first 🙂
American CrocodileOP
@American Crocodile Click to see attachment
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."