reactjsgatsbyreact-cookiereact-toggle

React-toggle, with react-cookie with a compiled gatsby build


I am trying to use react-toggle with react-cookie on a compiled Gatsby build.

For those that don't know, Gatsby compiles ReactJS into a static output (basically flat plain HTML with react on the client side.

I basically want to use React-toggle to toggle between checked/unchecked based from a cookie value.

The challenge here, is that because the code compiles to a static output, it seems to get run server side/before its compiled, so the defaultChecked needs to be accessed from it's own function. We do not want to access the cookie directly, it will be undefined anyway.

const Toggle = ({cookieName}) => {
  const [cookie, setCookie] = useCookies([cookieName]);
  const getCookieValue = () => typeof cookie[cookieName] === "undefined" ? false : cookie[cookieName] === "true" ? true : false;
  const setCookieValue = (e) => setCookie(cookieName, e.target.checked, {path: '/'});

  return (
    <ToggleWrap>
        <ReactToggle
          defaultChecked={getCookieValue()}
          icons={{
            checked: <ToggleText>Option 1</ToggleText>,
            unchecked: <ToggleText>Option 2</ToggleText>
          }}
          onChange={setCookieValue}
        />
    </ToggleWrap>
  )
};

Even though the cookie changes, the defaultChecked is always the same, this is the issue. (always false).


Solution

  • Okay you beautiful people, I used my noggin and actually solved it.

    const Toggle = ({metricString, imperialString, cookieName}) => {
    const [cookieValue, setCookieValue] = useCookies([cookieName]);
    const [checked, setChecked] = useState(false);
    
    const setCookie = (e) => {
      setChecked(JSON.parse(e.target.checked));
      setCookieValue(cookieName, e.target.checked, {path: '/'});
    };
    
    useEffect(() => {
      const getCookieValue = () => typeof cookieValue[cookieName] === "undefined" ? false : cookieValue[cookieName] === "true" ? true : false;
      setChecked(getCookieValue());
    }, [])
    
    return (
      <ToggleWrap>
          <StyledToggle
            checked={checked}
            icons={{
              checked: <ToggleText>{imperialString}</ToggleText>,
              unchecked: <ToggleText>{metricString}</ToggleText>
            }}
            onChange={setCookie}
          />
      </ToggleWrap>
    )
    

    };

    Check out the use of useEffect() there, I reminded myself it gets called on the client side!