Maison  >  Questions et réponses  >  le corps du texte

Les sous-composants React ne peuvent pas détecter les changements d'état des fonctions asynchrones dans useEffect

<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粉609866533P粉609866533384 Il y a quelques jours459

répondre à tous(1)je répondrai

  • P粉501007768

    P粉5010077682023-09-03 00:25:16

    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.

    répondre
    0
  • Annulerrépondre