thedevelobear/react-rewards

useReward can't find element if it's rendered conditionally

thedevelobear opened this issue · 1 comments

I'm aware of this issue and I'll fix it in the upcoming release. Here's an example of the code that doesn't work at the moment:


const SomeAsyncScreen = () => {
  const [ data, setData ] = useState(undefined);
  const { reward, isAnimating } = useReward("rewardId", "confetti");

  useEffect(() => {
    setTimeout(() => {
      setData({});
    }, 500);
  }, []);

  if (!data) return "Loading...";

  return (
    <div className="App">
      <span id="rewardId" /> 
      <button disabled={isAnimating} onClick={reward}>
        Make it rain!
      </button>
    </div>
  );
};

The problem is that the element is grabbed in useLayoutEffect, which fires synchronously after all DOM mutations. In this case there's no element with an id === "rewardId" on mount.

While I'm working on that, a possible solution would be to bring the target element one level up, or always render the element and make other parts of the screen conditional, like so:


const SomeAsyncScreen = () => {
  const [ data, setData ] = useState(undefined);
  const { reward, isAnimating } = useReward("rewardId", "confetti");

  useEffect(() => {
    setTimeout(() => {
      setData({});
    }, 500);
  }, []);

  return (
    <div className="App">
      <span id="rewardId" /> 
      {data && <SomeDataDependentJsx/>} 
      <button disabled={isAnimating} onClick={reward}>
        Make it rain!
      </button>
    </div>
  );
};