React subcomponents cannot sense state changes from asynchronous functions inside useEffect
P粉609866533
P粉609866533 2023-09-02 12:55:44
0
1
441

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.

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.

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 ( 
{ dataset && ( )}
); } export default App;

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粉609866533
P粉609866533

reply all (1)
P粉501007768

useStateRefseems 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.

function App({ width, height }) { const canvas = React.useRef() const [color, setColor] = React.useState("white") // when color changes.. React.useEffect(() => { if (canvas.current) { const context = canvas.current.getContext('2d'); context.fillStyle = color context.fillRect(0, 0, width, height) } }, [color, width, height]) return 
} ReactDOM.createRoot(document.querySelector("#app")).render()
canvas { display: block; border: 1px solid black; }
  

Or maybe there's no reason to store colors as state. You can create thesetColorfunction yourself and attach it as an event listener -

function App({ width, height }) { const canvas = React.useRef() const setColor = color => event => { if (canvas.current) { const context = canvas.current.getContext('2d'); context.fillStyle = color context.fillRect(0, 0, width, height) } } return 
} ReactDOM.createRoot(document.querySelector("#app")).render()
canvas { display: block; border: 1px solid black; }
  

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.

    Latest Downloads
    More>
    Web Effects
    Website Source Code
    Website Materials
    Front End Template
    About us Disclaimer Sitemap
    php.cn:Public welfare online PHP training,Help PHP learners grow quickly!