Skip to content

Commit

Permalink
[hierarchical-state] Work around double fetch with useRef (glad t…
Browse files Browse the repository at this point in the history
…o have re-learned this feature; the new React docs are nice)
  • Loading branch information
dgroomes committed Jan 16, 2024
1 parent bc43c62 commit 524f579
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 5 deletions.
10 changes: 10 additions & 0 deletions hierarchical-state/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ General clean-ups, todos and things I wish to implement for this project:
out of scope. I think I want like a global fetchCount state or something. Should I set it via props or use the Context API?
* Fix the double fetching problem. I think I need to push state up out of the GameDieRoll component. Not really sure.
I'm hoping to find multiple ways to solve this problem.
* DONE Work around the double fetching problem using a ref via `useRef`. It's hard to say what the "right" thing is to do
here. The spirit of React's strict mode is to help you find problems. I appreciate that it [finds usages of deprecated
APIs](https://react.dev/reference/react/StrictMode#fixing-deprecation-warnings-enabled-by-strict-mode) and the double
render is interesting and I think reasonable. I find the [re-running effects feature](https://react.dev/reference/react/StrictMode#fixing-bugs-found-by-re-running-effects-in-development)
to be aggressive and odd. I get that it will help you to literally stop and think about your `useEffect` calls because of
the double logging (although I'm shocked that they even considered suppressing the double render logs from the console
using React DevTools). I don't think it directly helps you to realize that there is a clean-up facility of `useEffect`.
For now, I'm going to use `useRef` and lock it in as a working example. But at this point I'm curious if I can just
take all my effect-ful code out of React. Can I use React for just rendering (as original React intended?) and have
the "rest of my program" as an organic JavaScript program?
## Reference
Expand Down
15 changes: 10 additions & 5 deletions hierarchical-state/src/GameDieRoll.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useEffect, useState} from "react";
import { mockFetch as fetch } from "./mockFetch";
import React, {useEffect, useRef, useState} from "react";
import {mockFetch as fetch} from "./mockFetch";

const gameDieNumberToAsciiArt = {
1: `
Expand Down Expand Up @@ -60,15 +60,18 @@ const loadingDieAsciiArt = `
export function GameDieRoll(props) {
console.log("[GameDieRoll] Render function invoked.");
const [gameDieRoll, setGameDieRoll] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [isLoading, setIsLoading] = useState(false);
// This is a hack to make sure that we only kick off one fetch request for the game die roll. React's strict mode
// triggers the effect twice and I would rather not make two fetch requests.
const fetchRef = useRef(null);

// This isn't right, I can't use this as a click handler because it basically makes a fetch outside of a useEffect
// callback, right? Again, I'm not sure how to do basic React programming.
const rollDice = () => {
props.incrementFetchCount();
setIsLoading(true);
console.log("[GameDieRoll] `useEffect` callback invoked. Making a 'fetch' request.");
fetch('/dice-roll')
fetchRef.current = fetch('/dice-roll')
.then(response => {
console.log("[GameDieRoll] `fetch` received a response.");
return response.json();
Expand All @@ -79,7 +82,9 @@ export function GameDieRoll(props) {
});
};

useEffect(rollDice, []); // Empty dependency array ensures this runs once on mount and not on every render
useEffect(() => {
if (fetchRef.current === null) rollDice();
}, []);

if (isLoading) {
return (
Expand Down

0 comments on commit 524f579

Please sign in to comment.