Les sous-composants React ne peuvent pas détecter les changements d'état des fonctions asynchrones dans useEffect
P粉609866533
P粉609866533 2023-09-02 12:55:44
0
1
535
<p>J'essaie de transmettre un état généré dans une fonction asynchrone, qui elle-même se trouve dans useState. J'ai appris que useRef est probablement le meilleur moyen de résoudre ce problème car il peut faire référence à un état mutable et, ce faisant, j'ai découvert React-useStateRef, qui a finalement résolu un autre problème où l'état à l'intérieur de mon composant principal n'a jamais été mis à jour. Problème (continue à obtenir " trop de rendus" erreurs). Il agit donc essentiellement comme useRef et useState réunis en un seul. </p> <p>Cependant, bien que mon état ait finalement été mis à jour, il n'a toujours pas été transmis à mon composant Canvas. J'essaie de mettre à jour le graphique BG d'une toile en fonction des températures obtenues à partir d'un ensemble de données. </p> <pre class="brush:php;toolbar:false;">import { useEffect } depuis 'react'; importer useState depuis 'react-usestateref' ; importer { getServerData } depuis './serviceData' ; importer "./App.css" importer Canvas depuis './components/Canvas' ; fonction App() { const [ensemble de données, setDataset] = useState(null); const [unités, setUnits] = useState('metric'); // trucs graphiques de fond de toile var [currentBG, setCurrentBG, currentBGref] = useState(null); useEffect(() => { const fetchServerData = async () => const data = wait getServerData(ville, unités); setDataset(données); fonction updateBG() { const seuil = unités === "métrique" 20 : 60 ; if (data.temp <= seuil) { setCurrentBG('neige'); } autre { setCurrentBG('ensoleillé'); } } updateBG(); } fetchServerData(); console.log (BG actuel) }, [ville, unités, currentBGref.current, currentFGref.current]) const isCelsius = currentUnit === "C"; bouton.innerText = isCelsius ? "°F" : "°C"; setUnits(isCelsius ? "metric" : "impérial"); } ; retour ( <div className="app"> { ensemble de données && ( <Largeur du canevas={640} hauteur={480} currentBG={currentBGref.current}></Canvas> )} </div> ); } exporter l'application par défaut ;</pre> <p>Je ne peux transmettre que la valeur initiale et elle ne se met jamais à jour au-delà, bien que le fichier console.log dans useEffect montre qu'il est définitivement mis à jour. Alors pourquoi n'est-il pas transmis à mon composant ? </p>
P粉609866533
P粉609866533

répondre à tous(1)
P粉501007768

useStateRef semble être un anti-modèle. Vous décidez quel est le nouvel état, donc si vous avez besoin d’une autre référence, vous pouvez toujours en créer une vous-même. Je recommande de minimiser les propriétés sur le canevas pour éviter un nouveau rendu inutile.

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 <div>
    <canvas ref={canvas} width={width} height={height} />
    <button onClick={_ => setColor("blue")} children="blue" />
    <button onClick={_ => setColor("green")} children="green" />
    <button onClick={_ => setColor("red")} children="red" />
  </div>
}

ReactDOM.createRoot(document.querySelector("#app")).render(<App width={200} height={150} />)
canvas { display: block; border: 1px solid black; }
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

Ou peut-être qu'il n'y a aucune raison de stocker les couleurs en tant qu'état. Vous pouvez créer vous-même la fonction setColor et la joindre en tant qu'écouteur d'événement -

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 <div>
    <canvas ref={canvas} width={width} height={height} />
    <button onClick={setColor("blue")} children="blue" />
    <button onClick={setColor("green")} children="green" />
    <button onClick={setColor("red")} children="red" />
  </div>
}

ReactDOM.createRoot(document.querySelector("#app")).render(<App width={200} height={150} />)
canvas { display: block; border: 1px solid black; }
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

Je recommande également de consulter SVG. Je trouve que l'API SVG correspond mieux au modèle React que l'API Canvas. Les capacités de chacun sont différentes, mais si SVG répond à vos besoins, cela vaut la peine d'y réfléchir.

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal