1

I have a banner that has it's visibility determined by the state of true or false. I have a close button with a clickHandler to set state to false, which hides the banner. When I navigate to a different page, the state resets to true, therefore the banner is visible.

How do I force the state to remain false, even if page refreshes or changes? Basically, I want the banner to not appear again, if the user closes it.

Note: Banner component is used a Layout component, which is used by all pages.

const BannerWrapper = styled.div`
  visibility: ${props => (props.show ? "visible" : "hidden")};
`

const CloseIcon = styled.div`
  position: absolute;
  cursor: pointer;
`

const Banner = () => {
  const [show, setShow] = useState(true)

  const handleClick = () => {
    setShow(false)
  }

  return (
    <BannerWrapper show={show}>
      Some Banner Content
       <CloseIcon onClick={handleClick}>
        X
      </CloseIcon>
    </BannerWrapper>
  )
}

export default Banner
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Eric Nguyen
  • 926
  • 3
  • 15
  • 37
  • This banner should be present only in a specific route? – Medi Apr 28 '21 at 18:13
  • you have to manage state in a parent elem(like app.js). Cuz everytime the page where this component is rendered the default value will be true. – Adarsh Apr 28 '21 at 18:18

2 Answers2

2

You can persist the state to localStorage. Use a state initializer function to read in the state when the component mounts, and an useEffect hook to save/persist state updates to storage.

const Banner = () => {
  const [show, setShow] = useState(() => {
    const showBanner = localStorage.getItem('showBanner');
    // if showBanner null/undefined fallback to true
    return JSON.parse(showBanner) ?? true;
  });

  React.useEffect(() => {
    localStorage.setItem('showBanner', JSON.stringify(show));
  }, [show]);

  const handleClick = () => {
    setShow(false);
  };

  return (
    <BannerWrapper show={show}>
      Some Banner Content
       <CloseIcon onClick={handleClick}>
        X
      </CloseIcon>
    </BannerWrapper>
  );
}

Edit force-state-to-maintain-boolean-value

Update - To "reset" and display banner.

If you want/need to reset to once again display the banner then I believe any of the following will do the trick:

  • Remove it from localStorage: localStorage.removeItem('showBanner');
  • Set it true: localStorage.setItem('showBanner', JSON.stringify(true));
  • Set it null: localStorage.setItem('showBanner', null);

IMO removing it from localStorage is the cleanest option.

You could OFC also update the show state locally:

const enableBanner = () => setShow(true);

This will update the state and trigger the effect to persist the updated state value.

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • 1
    I think OP wants to have banner open initially...I think you should read value from localStorage as initial value of `useState`(if it is not undefined) – Giorgi Moniava Apr 28 '21 at 18:25
  • You could also put logic of first `useEffect` inside `useState` instead, but it is up to you :) – Giorgi Moniava Apr 28 '21 at 18:29
  • 1
    @gmoniava Right, good call, was doing that as you made second comment. :) – Drew Reese Apr 28 '21 at 18:30
  • I like this idea, however it doesn't appear to be working. I do see in local storage, `showBanner` initiates as `true` and after closing, it changes to `false` and maintains that `false` value, however the banner still shows up? – Eric Nguyen Apr 28 '21 at 18:32
  • @EricNguyen I didn't think it would matter with a plain boolean value, but the values going to localStorage still need to be JSON serialized. I updated my answer and included a running codesandbox. Sorry for any confusion and delay. – Drew Reese Apr 28 '21 at 18:54
  • Very nice @DrewReese If I ever need to update that localStorage value `showBanner` back to true, what's the best approach of doing so? – Eric Nguyen Apr 28 '21 at 20:24
  • @EricNguyen I updated my answer with some options for toggling back on the banner. – Drew Reese Apr 28 '21 at 20:35
1

The answer to the question of "how do I persist values across page refresh" is: use local storage. There are hooks that implement the same kind of interface of useState, but store the value in the local storage instead of in memory under the hood. One of those is useLocalStorage ( https://usehooks.com/useLocalStorage/ ).

Federkun
  • 36,084
  • 8
  • 78
  • 90