React subcomponents cannot sense state changes from asynchronous functions inside useEffect
P粉609866533
2023-09-02 12:55:44
<p>I'm trying to pass a state generated inside an async function, which itself is inside useState. I learned that useRef is probably the best way to solve this problem because it can reference mutable state, and in the process learned about React-useStateRef, which finally solved another problem where the state inside my main component was never updated Problem (keeps getting "too many renders" errors). So it essentially acts as useRef and useState rolled into one. </p>
<p>However, although my state finally updated, it still wasn't passed to my Canvas component. I'm trying to update a canvas's BG graph based on the temperatures obtained from a dataset. </p>
<pre class="brush:php;toolbar:false;">import { useEffect } from 'react';
import useState from 'react-usestateref';
import { getServerData } from './serviceData';
import "./App.css"
import Canvas from './components/Canvas';
function App() {
const [dataset, setDataset] = useState(null);
const [units, setUnits] = useState('metric');
// canvas background graphic stuff
var [currentBG, setCurrentBG, currentBGref] = useState(null);
useEffect(() => {
const fetchServerData = async () => {
const data = await getServerData(city, units);
setDataset(data);
function updateBG() {
const threshold = units === "metric" ? 20 : 60;
if (data.temp <= threshold) {
setCurrentBG('snow');
}
else {
setCurrentBG('sunny');
}
}
updateBG();
}
fetchServerData();
console.log(currentBG)
}, [city, units, currentBGref.current, currentFGref.current])
const isCelsius = currentUnit === "C";
button.innerText = isCelsius ? "°F" : "°C";
setUnits(isCelsius ? "metric" : "imperial");
};
return (
<div className="app">
{ dataset && ( <Canvas width={640} height={480} currentBG={currentBGref.current}></Canvas> )}
</div>
);
}
export default App;</pre>
<p>I can only pass the initial value and it never updates past that, although the console.log inside useEffect shows that it is definitely updating. So why isn't it being passed to my component? </p>
useStateRef
seems to be an anti-pattern. You decide what the new state is, so if you need another reference to it, you can always create one yourself. I recommend minimizing the properties on the canvas to prevent unnecessary re-rendering.Or maybe there's no reason to store colors as state. You can create the
setColor
function yourself and attach it as an event listener -I also recommend checking out SVG. I find that the SVG API fits the React pattern better than the Canvas API. The capabilities of each are different, but if SVG works for your needs, it's worth considering.