React: Bug : trop difficile à corriger "Impossible de mettre à jour un composant depuis le corps de la fonction d'un autre composant."

Créé le 28 févr. 2020  ·  109Commentaires  ·  Source: facebook/react

# Remarque : React 16.13.1 a corrigé certains cas de surchauffe. Si la mise à niveau de React et ReactDOM vers 16.13.1 ne résout pas l'avertissement, lisez ceci : https://github.com/facebook/react/issues/18178#issuecomment -595846312

Réagir version :

16.13.0

Étapes à reproduire

  1. Construisez une machine à remonter le temps.
  2. Allez à l'année 2017.
  3. Construisez une énorme application de 10 000 lignes de code.
  4. Obtenez 80 (!) Dépendances dans le fichier package.json, y compris celles qui ne sont plus maintenues.
  5. Mettez à jour React vers la dernière version le 27 février 2020.
  6. Obtenez des tonnes d'erreurs que vous ne savez pas comment corriger.
  7. Dites à votre client que les correctifs vont prendre un temps inconnu et que cela va coûter $$$ + jours ou semaines d'enquête ou nous allons rester coincés avec la version obsolète de React et des bibliothèques associées pour toujours, ce qui coûtera plus de $$$ mais plus tard.

Étant sérieux, l'entreprise pour laquelle je travaille ne s'intéresse pas du tout à cela. De toute évidence, je n'avais jamais réussi à faire apparaître de tels avertissements si je les avais reçus plus tôt. Actuellement, il est incroyablement difficile de corriger les erreurs car je les reçois dans de nombreux cas différents et avec une énorme trace de pile. J'ai essayé de corriger au moins une des erreurs apparaissant et cela a déjà pris beaucoup de temps. J'ai essayé de déboguer certaines des bibliothèques utilisées mais je n'ai pas eu de chance.

Juste un exemple :

image

Là, nous pouvons remarquer l'utilisation d'un routeur de réaction obsolète, d'un redux-connect obsolète (que j'ai dû mettre au source du projet pour corriger les erreurs de la méthode componentWillReceiveProps obsolète), certains HOC créés par recompose etc. Il n'est pas seulement un simple arbre DOM virtuel où je peux parcourir les composants que j'ai développés et rechercher par chaîne setState pour corriger le bogue, c'est bien plus compliqué que cela.

Veuillez créer une option "UNSAFE" pour désactiver cette erreur ou fournir un moyen plus simple de trouver où l'erreur est levée 🙏

Discussion

Commentaire le plus utile

Aux futurs commentateurs. Je comprends que voir un nouvel avertissement est frustrant. Mais il signale des problèmes légitimes qui sont probablement à l'origine de bogues dans votre code . Nous vous serions très reconnaissants si vous pouviez vous abstenir d'exprimer des sarcasmes et de l'agacement.

Si vous ne pouvez pas comprendre d'où cela vient dans les traces de la pile, veuillez publier des captures d'écran ou créer des bacs à sable reproduisant et nous essaierons de vous aider. La plupart d'entre eux proviennent probablement de quelques bibliothèques, donc la chose la plus productive à faire est de réduire ces cas, puis de signaler les problèmes avec ces bibliothèques.

Merci à tous.

Tous les 109 commentaires

J'aurais aimé que nous ayons ajouté cet avertissement plus tôt. Je suis désolé que nous ne l'ayons pas fait. C'était un oubli avec l'introduction de Hooks. Je pense que cela doit être causé par un code plus récent qui utilise des Hooks, car il y avait déjà le même avertissement pour les classes beaucoup plus tôt, donc tout code antérieur aurait déjà vu cet avertissement.

Notez que cela commencera probablement à échouer dans les futures versions de React. Intentionnel ou non (nous avons eu beaucoup de bugs avec ce modèle). Donc, peu importe, vous pourriez vous retrouver bloqué sur une ancienne version. S'il n'est pas possible de le réparer, je vous recommande de l'épingler sur une ancienne version de React.

Cependant, cela dit, nous voulons vous aider et faciliter autant que possible la résolution de ces problèmes, notamment en voyant si nous pouvons obtenir de l'aide des auteurs de bibliothèques pour publier des versions corrigées.

Si vous développez la petite flèche > dans la console Chrome, vous devriez également voir une trace de pile supplémentaire (en plus de la pile de composants dans votre capture d'écran). Peux-tu poster ça aussi ? Cela devrait vous montrer le site d'appel exact qui provoque un effet secondaire dans le rendu.

Avec moi, cela apparaît lorsque j'utilise formik

image

@sebmarkbage merci pour la réponse. Le stacktrace apparaissant après avoir cliqué sur > est ridicule. Il contient plus de 200 articles !

J'allais le coller là ou donner un lien vers pastebin mais j'ai essayé une direction différente. J'ai parcouru les problèmes Github de certaines des bibliothèques utilisées et découvert que l'un des suspects est redux-form : https://github.com/redux-form/redux-form/issues/4619. J'espère que c'est la seule bibliothèque qui provoque les erreurs et je vais attendre un correctif avant de mettre à niveau React.

Mais quand même, je demanderais de ne pas fermer ce problème et je propose aux autres développeurs de mentionner ici les bibliothèques qui provoquent également ces erreurs.

@RodolfoSilva êtes-vous sûr que c'est causé par le formik ? Si oui, pouvez-vous s'il vous plaît créer un problème là-bas et poster un lien vers celui-ci ici ? Je vais créer une liste de ces problèmes au début de mon premier message si la liste doit contenir plus d'un élément.

Cela doit vraiment être abordé dès que possible. Cela rend la mise à niveau impossible. La trace d'erreur est pratiquement impossible.

Hum. Je me demande si décrire la ligne à rechercher dans le message d'erreur serait utile.

Dans ce cas, la première ligne à rechercher est la ligne après dispatchAction . Cela devrait être la chose qui appelle React.

@RodolfoSilva pouvez-vous publier la source de FormItemInput.js , si c'est quelque chose que vous pouvez partager ? Cela semble appeler dispatch ou setState sur la ligne 71.

Je pense qu'il est impératif que ce message d'erreur soit modifié pour inclure exactement quelle ligne de code est à l'origine de l'erreur. Il est presque impossible de déterminer si c'est le code local ou le code de bibliothèque qui cause le problème. Les bibliothèques externes telles que react-redux et react-router sont probablement les coupables, mais il est impossible de le déterminer facilement.

Je suis à peu près sûr que React-Redux n'est pas en cause ici, mais j'ai convenu que le message d'erreur et la pile de composants rendent difficile de savoir ce qui se passe réellement.

Je rencontre le même problème avec Redux-form!

J'ai le même problème et je vois que l'avertissement s'affiche la première fois que j'écris dans mon champ redux ou lorsque j'efface tout

J'ai aussi ce problème, voici mon composant :

`const [prix, setPrice] = useState(0) ;

const updatePrice = (newPrice) => {
setPrice(nouveauPrix)
}
< CardContainer onPriceUpdated={updatePrice} > CardContainer >
`

Donc, dans ce cas, mon composant CardContainer, notifie au composant parent lorsque le prix est mis à jour et que le composant parent rend le nouveau prince.
Je suppose donc que React m'avertit que j'essaie de mettre à jour l'état d'un composant en utilisant la fonction d'un autre composant.
Je suis nouveau dans React, donc je ne sais pas s'il s'agit d'un modèle React ou s'il s'agit en fait d'un bug.

Si vous avez des suggestions pour résoudre cet avertissement, je vous en serais reconnaissant``

@l0gicgate

Je pense qu'il est impératif que ce message d'erreur soit modifié pour inclure exactement quelle ligne de code est à l'origine de l'erreur.

Il y a des limites à ce que nous pouvons faire en JavaScript. Mais toutes les informations sont dans la pile que vous voyez dans le navigateur . Tout ce que vous avez à faire est de sauter les lignes qui se trouvent dans React.

Pour voir la pile JavaScript, vous devez cliquer sur une petite flèche à côté du message d'erreur .

Par exemple, regardez cette capture d'écran précédemment :

75614021-cb812980-5b12-11ea-8a6e-a38f4cd6aeef

Je comprends que c'est un peu ennuyeux de fouiller dans la pile, mais il ne devrait pas être si difficile de sauter les premières images. La trame suivante est la source du problème. Dans ce cas, cela ressemble à quelque chose à l'intérieur de la bibliothèque Formik. Vous pouvez donc lui signaler un problème.

@martinezwilmer Cet exemple est trop petit pour être utile. Créez un bac à sable s'il vous plaît.

Aux futurs commentateurs. Je comprends que voir un nouvel avertissement est frustrant. Mais il signale des problèmes légitimes qui sont probablement à l'origine de bogues dans votre code . Nous vous serions très reconnaissants si vous pouviez vous abstenir d'exprimer des sarcasmes et de l'agacement.

Si vous ne pouvez pas comprendre d'où cela vient dans les traces de la pile, veuillez publier des captures d'écran ou créer des bacs à sable reproduisant et nous essaierons de vous aider. La plupart d'entre eux proviennent probablement de quelques bibliothèques, donc la chose la plus productive à faire est de réduire ces cas, puis de signaler les problèmes avec ces bibliothèques.

Merci à tous.

Difficile de trouver la ligne précise concernée par l'avertissement ici :

@gaearon avez-vous encore une astuce à ce sujet ?

image

Difficile de trouver la ligne précise concernée par l'avertissement ici :

Qu'est-ce qui le rend difficile? Comme je l'ai noté ci-dessus, c'est la première ligne qui ne dit pas « réagir » sur le côté droit. Dans ce cas, il s'agit de connectAdvanced de Redux. Veuillez signaler un problème dans React Redux afin que les responsables aient la possibilité de l'examiner.

Comme je l'ai dit en amont, je serais _très_ surpris si ce qui se passe ici est un problème avec React-Redux.

Cela dit, je ne sais même pas exactement ce qui déclenche ce message en premier lieu. Je comprends à moitié ce que dit le message d'erreur, mais quel type de modèle de code d'application serait en fait un exemple de ce comportement ?

Je suis tombé sur cette récemment et le correctif enveloppait setState les sites d'appel de gestionnaire dans useEffect , comme suit: https://github.com/airbnb/lunar/commit/db08613d46ea21089ead3e7b5cfff995f15c69a7#diff -1c3bdd397b1ce5064142488877045306R56 ( onChange et onSubmit utilisez setState plus haut dans la chaîne).

@martinezwilmer Où est onPriceUpdated ? Essayez peut-être de l'envelopper dans useEffect ?

Le même problème semble se produire pour urql

Nous utilisons use-subscription + wonka (pour les flux) pour orchestrer nos mises à jour, mais une mise à jour peut arriver de manière synchrone. Ici, nous avons déjà récupéré le todos donc si nous cliquons sur le bouton Open le résultat devrait apparaître instantanément, mais cela semble déclencher l'erreur suivante.

image

Dans notre cas, cela est voulu, nous ne pouvons pas simplement afficher fetching: true pour un résultat de synchronisation, ce qui entraînerait des interfaces nerveuses.

Cela commence à apparaître de plus en plus dans les bibliothèques tierces maintenant : urql , Apollo .

J'ai rencontré cela et pendant plusieurs heures, j'ai supposé que le problème était dans mon code. Le stacktrace condensé pointe vers mes composants, et il n'est pas inhabituel pour moi de voir des bibliothèques tierces dans le stacktrace étendu lorsque j'ai déclenché explicitement une erreur. D'après mes recherches (bien que limitées) sur cet avertissement particulier, il semble que la plupart des développeurs ne sont pas à l'origine de ce problème eux-mêmes, mais dépendent plutôt du code qui le fait. Il est généralement recommandé de supposer qu'il ne s'agit pas d'un bogue en amont, mais lorsqu'il s'agit d'un bogue en amont, perdre du temps à rechercher un problème dans votre code qui n'existe pas est plutôt frustrant. Y a-t-il quelque chose que React puisse faire pour aider un utilisateur moyen à déterminer s'il s'agit du code qu'il a écrit ou du code dont il dépend qui a causé le problème ?

Une chose que je note du problème d'Apollo est :

Le stacktrace de l'avertissement montre le composant qui a paraphé les modifications, pas celui qui est rendu à nouveau [sic] par ces modifications

Si cela est correct, React peut-il donner plus d'informations ici ? Peut-être nous dire à la fois le composant initiateur et les composants qu'il a fait mettre à jour ?

Comme @hugo , j'ai rencontré ceci lors du test d' une nouvelle application Ionic :

  1. npx ionic start demo sidemenu --type=react
  2. react-scripts test

En effet, la cause est enfouie au milieu et en bas de la trace de la pile.

console.error node_modules/react-dom/cjs/react-dom.development.js:88
    Warning: Cannot update a component from inside the function body of a different component.
        in Route (at App.tsx:37)
        in View (created by StackManagerInner)
        in ViewTransitionManager (created by StackManagerInner)
        in ion-router-outlet (created by IonRouterOutlet)
        in IonRouterOutlet (created by ForwardRef(IonRouterOutlet))
        in ForwardRef(IonRouterOutlet) (created by StackManagerInner)
        in StackManagerInner (created by Context.Consumer)
        in Unknown (created by Component)
        in Component (created by ForwardRef(IonRouterOutlet))
        in ForwardRef(IonRouterOutlet) (at App.tsx:36)
        in ion-split-pane (created by IonSplitPane)
        in IonSplitPane (created by ForwardRef(IonSplitPane))
        in ForwardRef(IonSplitPane) (at App.tsx:34)
        in NavManager (created by RouteManager)
        in RouteManager (created by Context.Consumer)
        in RouteManager (created by IonReactRouter)
        in Router (created by BrowserRouter)
        in BrowserRouter (created by IonReactRouter)
        in IonReactRouter (at App.tsx:33)
        in ion-app (created by IonApp)
        in IonApp (created by ForwardRef(IonApp))
        in ForwardRef(IonApp) (at App.tsx:32)
        in App (at App.test.tsx:6)

Ce problème était le plus proche que j'ai pu trouver concernant ce problème.

Nous avons trouvé un modèle spécifique qui provoque ce problème avec mobx over dans https://github.com/mobxjs/mobx-react/issues/846

@sebmarkbage je ne peux plus reproduire ce problème. Nous avons mis à jour certaines bibliothèques et les problèmes sont terminés.

@jgoux nous semblons faire face au même problème @Clovis ^^ Repéré

J'ai commencé à avoir cette erreur après que la mise à jour ait réagi à react 16.13.0 . Le problème est assez clair car l'un de mes composants en met à jour un autre après qu'une action spécifique a été effectuée. Cependant, je ne sais pas pourquoi cela lancerait un avertissement. Une suggestion sur la façon de contourner cela?

@gaearon merci pour les détails sur la façon de déboguer à partir de la pile, personnellement, je n'aurais pas pu comprendre d'où venait cette erreur si vous n'aviez pas donné cet exemple. ??

Cependant, je ne sais pas si mon problème est lié, j'essaie de mettre à jour l'état de mon composant de formulaire, mais chaque fois que j'essaie d'ajouter un gestionnaire onChange, il continue de me donner cette erreur. Remarquez, j'utilise react-jsonschema-form et j'ai importé le composant Form et j'utilise sa propriété onChange pour mettre à jour l'état.

Pour moi, c'est le modèle qui cause le problème.

image

Il y a peut-être un moyen de contourner cela. Mais le journal de la console m'a dirigé directement vers la ligne 385

Je suis nouveau pour réagir mais j'avais un code comme celui-ci :

import React, { useState } from "react";

function Home() {
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>}
    </div>
  );
}

function MobileNav() {
  return (
    <div>
      <button
        onClick={setMobileNavOpen(false)} //problem here
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

Ce qui a donné : Cannot update a component from inside the function body of a different component.

Tout ce que j'avais à faire était d'ajouter une fonction flèche à setMobileNavOpen dans MobileNav comme ceci :

import React, { useState } from "react";

function Home() {
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>}
    </div>
  );
}

function MobileNav() {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(false)} //fixes problem
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

Et cela résout le problème, j'espère que cela aidera quelqu'un!

Je suis nouveau pour réagir mais j'avais un code comme celui-ci :

import React, { useState } from "react";

function Home() {
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>}
    </div>
  );
}

function MobileNav() {
  return (
    <div>
      <button
        onClick={setMobileNavOpen(false)} //problem here
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

Ce qui a donné : Cannot update a component from inside the function body of a different component.

Tout ce que j'avais à faire était d'ajouter une fonction flèche à setMobileNavOpen dans MobileNav comme ceci :

import React, { useState } from "react";

function Home() {
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>}
    </div>
  );
}

function MobileNav() {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(false)} //fixes problem
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

Et cela résout le problème, j'espère que cela aidera quelqu'un!

Votre exemple est en fait l'une des premières erreurs que les gens font avec réagir. Je ne suis pas sûr que ce soit exactement le même problème qui est discuté ici. Votre ligne ici : onClick={setMobileNavOpen(false) appelle la fonction pendant l'appel du bouton, pas au clic. C'est pourquoi l'envelopper dans une fonction de flèche le corrige.

J'ai rencontré ce problème avec React Router où je devais envoyer une action Redux avant <Redirect> envoyer l'utilisateur à un autre emplacement. Le problème semblait être que la redirection s'est produite avant la fin de l'envoi. J'ai résolu le problème en promettant mon action.

Avant:

<Route
  render={routeProps => {
    setRedirectionTarget(somePath(routeProps));
    return <Redirect to={someOtherPath} />;
  }}
/>;

function mapDispatchToProps(dispatch: ThunkDispatch) {
  return {
    setRedirectionTarget: (target: string | null) => dispatch(setRedirectionTarget(target))
  };
}

export const setRedirectionTarget = (location: string | null): SetRedirectionTarget => {
  return {
    type: SET_REDIRECTION_TARGET,
    location
  };
};

Après:

function mapDispatchToProps(dispatch: ThunkDispatch) {
  return {
    setRedirectionTarget: async (target: string | null) => dispatch(await setRedirectionTarget(target))
  };
}

export const setRedirectionTarget = (location: string | null): Promise<SetRedirectionTarget> => {
  return Promise.resolve({
    type: SET_REDIRECTION_TARGET,
    location
  });
};

Je pense qu'il faudrait faire en sorte que le message d'erreur inclue des noms à la fois pour le composant en cours de rendu et pour le composant dont setState est appelé. Est-ce que n'importe qui veut envoyer un PR pour ceci ?

Je pense qu'il faudrait faire en sorte que le message d'erreur inclue des noms à la fois pour le composant en cours de rendu et pour le composant dont setState est appelé. Est-ce que n'importe qui veut envoyer un PR pour ceci ?

Je suis heureux de jeter un œil à cela. Des conseils dont je devrais être au courant?

@samcooke98 J'ai ouvert un PR pour cela https://github.com/facebook/react/pull/18316

Comme d'autres l'ont souligné, vous pouvez rencontrer ce problème si vous avez un abonnement à un hook comme avec Apollo et essayez de mettre à jour un magasin lors de la réception de données. Une solution simple consiste à utiliser useEffect par exemple

export const useOrderbookSubscription = marketId => {
  const { data, error, loading } = useSubscription(ORDERBOOK_SUBSCRIPTION, {
    variables: {
      marketId,
    },
  })

  const formattedData = useMemo(() => {
    // Don't dispatch in here.
  }, [data])

  // Don't dispatch here either

  // Dispatch in a useEffect
  useEffect(() => {
    orderbookStore.dispatch(setOrderbookData(formattedData))
  }, [formattedData])

  return { data: formattedData, error, loading }
}

Nous étions confrontés à ce problème dans Hyper mais nous n'utilisons pas de hooks et nous n'avons rien trouvé dans l'appel de rendu de la pile d'appels. Mais il y avait un appel en UNSAFE_componentWillReceiveProps dans la pile. La mise à jour avec componentDidUpdate résolu le problème pour nous https://github.com/zeit/hyper/pull/4382
Posté ici si ça peut aider quelqu'un

Idem ici, il y a eu un appel UNSAFE_componentWillMount, le changer/supprimer a résolu le problème

mais nous n'utilisons pas de crochets et nous n'avons rien trouvé dans l'appel de rendu de la pile d'appels

Cela semble étrange. Je ne sais pas comment vous obtenez cet avertissement alors. Il ne se déclenche que si setState appartient à un composant de fonction. À quoi ressemble votre pile ?

mais nous n'utilisons pas de crochets et nous n'avons rien trouvé dans l'appel de rendu de la pile d'appels

Cela semble étrange. Je ne sais pas comment vous obtenez cet avertissement alors. Il ne se déclenche que si setState appartient à un composant de fonction. À quoi ressemble votre pile ?

Composants de classe avec Redux et fonctions qui appliquent des plugins aux composants. C'est peut-être pour ça qu'il est compté comme un composant de fonction ? Mais alors pourquoi la mise à jour des hooks du cycle de vie le résout-elle ?

Je ne suis pas sûr. Pouvez-vous essayer de créer un exemple isolé dans un bac à sable ? J'ai l'impression que vous pourriez faire autre chose d'inattendu.

Je ne sais pas si je pourrais le reproduire dans un exemple isolé. J'ai eu du mal à en trouver la cause et je venais de mettre à jour le hook du cycle de vie car il se trouvait dans la trace de la pile et était en attente de mise à jour. Cela a en quelque sorte résolu le problème.
Vous pouvez jeter un œil au repo au moment où il a eu le problème ici

Cela peut-il être dû au fait que UNSAFE_componentWillReceiveProps et componentDidUpdate trouvaient dans le composant à ce moment-là (un élément dangereux y a été laissé par erreur) ?

Je reçois également cet avertissement et la trace de la pile pointe vers le crochet setScriptLoaded (voir ci-dessous pour mon crochet personnalisé). Il semble donc que même si j'utilise useEffect , React lancera toujours un avertissement si le gestionnaire setState est imbriqué dans d'autres rappels asynchrones (dans mon cas, il est imbriqué dans un setTimeout et un gestionnaire d'événements load ) ? Ma première fois que j'utilise Hooks, j'apprécierais donc tout conseil. Merci!

/**
 * Detect when 3rd party script is ready to use
 * 
 * <strong i="11">@param</strong> {function} verifyScriptLoaded Callback to verify if script loaded correctly
 * <strong i="12">@param</strong> {string} scriptTagId 
 */

export const useScriptLoadStatus = (verifyScriptLoaded, scriptTagId) => {
    let initLoadStatus = true; // HTML already includes script tag when rendered server-side
    if (__BROWSER__) {
        initLoadStatus = typeof verifyScriptLoaded === 'function' ? verifyScriptLoaded() : false;
    }
    const [isScriptLoaded, setScriptLoaded] = useState(initLoadStatus); 

    useEffect(() => {
        if (!isScriptLoaded) {
            // need to wrap in setTimeout because Helmet appends the script tags async-ly after component mounts (https://github.com/nfl/react-helmet/issues/146)
            setTimeout(() => {
                let newScriptTag = document.querySelector(`#${scriptTagId}`);
                if (newScriptTag && typeof verifyScriptLoaded === 'function') {
                    newScriptTag.addEventListener('load', () => { 
                        return verifyScriptLoaded() ? setScriptLoaded(true) : null;
                    });
                    // double check if script is already loaded before the event listener is added
                    return verifyScriptLoaded() ? setScriptLoaded(true) : null;
                }
            }, 100);
        }
    });

    return isScriptLoaded;
};

@LabhanshAgrawal

Cela peut-il être dû au fait que UNSAFE_componentWillReceiveProps et componentDidUpdate étaient dans le composant à ce moment-là (un non sécurisé y a été laissé par erreur) ?

Je ne pense pas du tout que les méthodes de cycle de vie soient pertinentes ici. C'est pourquoi je dis que quelque chose est étrange dans votre exemple.

@suhanw Veuillez fournir un exemple complet dans CodeSandbox. Je ne vois aucun problème avec votre code qui devrait être à l'origine de cet avertissement.

@LabhanshAgrawal Pouvez-vous publier votre pile complète s'il vous plaît ? Je pense que ce qui peut se passer, c'est que votre UNSAFE_componentWillReceiveProps (qui équivaut au rendu) appelle setState sur un autre composant.

backend.js:6 Warning: Cannot update a component from inside the function body of a different component.
    in Term                           (created by _exposeDecorated(Term))
    in _exposeDecorated(Term)         (created by DecoratedComponent)
    in DecoratedComponent             (created by TermGroup_)
    in TermGroup_                     (created by ConnectFunction)
    in ConnectFunction                (created by Connect(TermGroup_))
    in Connect(TermGroup_)            (created by _exposeDecorated(TermGroup))
    in _exposeDecorated(TermGroup)    (created by DecoratedComponent)
    in DecoratedComponent             (created by Terms)
    in div                            (created by Terms)
    in div                            (created by Terms)
    in Terms                          (created by _exposeDecorated(Terms))
    in _exposeDecorated(Terms)        (created by DecoratedComponent)
    in DecoratedComponent             (created by ConnectFunction)
    in ConnectFunction                (created by Connect(DecoratedComponent))
    in Connect(DecoratedComponent)    (created by Hyper)
    in div                            (created by Hyper)
    in div                            (created by Hyper)
    in Hyper                          (created by _exposeDecorated(Hyper))
    in _exposeDecorated(Hyper)        (created by DecoratedComponent)
    in DecoratedComponent             (created by ConnectFunction)
    in ConnectFunction                (created by Connect(DecoratedComponent))
    in Connect(DecoratedComponent)
    in Provider
r                                     @ backend.js:6
printWarning                          @ react-dom.development.js:88
error                                 @ react-dom.development.js:60
warnAboutRenderPhaseUpdatesInDEV      @ react-dom.development.js:23260
scheduleUpdateOnFiber                 @ react-dom.development.js:21196
dispatchAction                        @ react-dom.development.js:15682
checkForUpdates                       @ connectAdvanced.js:88
handleChangeWrapper                   @ Subscription.js:97
(anonymous)                           @ Subscription.js:23
batchedUpdates$1                      @ react-dom.development.js:21887
notify                                @ Subscription.js:19
notifyNestedSubs                      @ Subscription.js:92
checkForUpdates                       @ connectAdvanced.js:77
handleChangeWrapper                   @ Subscription.js:97
(anonymous)                           @ Subscription.js:23
batchedUpdates$1                      @ react-dom.development.js:21887
notify                                @ Subscription.js:19
notifyNestedSubs                      @ Subscription.js:92
handleChangeWrapper                   @ Subscription.js:97
dispatch                              @ redux.js:222
e                                     @ VM64:1
(anonymous)                           @ effects.ts:11
(anonymous)                           @ write-middleware.ts:14
(anonymous)                           @ index.js:11
(anonymous)                           @ plugins.ts:538
(anonymous)                           @ plugins.ts:540
(anonymous)                           @ index.js:11
dispatch                              @ redux.js:638
(anonymous)                           @ sessions.ts:124
(anonymous)                           @ index.js:8
dispatch                              @ VM64:1
onResize                              @ terms.ts:62
(anonymous)                           @ term.js:179
e.fire                                @ xterm.js:1
t.resize                              @ xterm.js:1
e.resize                              @ xterm.js:1
e.fit                                 @ xterm-addon-fit.js:1
fitResize                             @ term.js:291
UNSAFE_componentWillReceiveProps      @ term.js:408
callComponentWillReceiveProps         @ react-dom.development.js:12998
updateClassInstance                   @ react-dom.development.js:13200
updateClassComponent                  @ react-dom.development.js:17131
beginWork                             @ react-dom.development.js:18653
beginWork$1                           @ react-dom.development.js:23210
performUnitOfWork                     @ react-dom.development.js:22185
workLoopSync                          @ react-dom.development.js:22161
performSyncWorkOnRoot                 @ react-dom.development.js:21787
(anonymous)                           @ react-dom.development.js:11111
unstable_runWithPriority              @ scheduler.development.js:653
runWithPriority$1                     @ react-dom.development.js:11061
flushSyncCallbackQueueImpl            @ react-dom.development.js:11106
flushSyncCallbackQueue                @ react-dom.development.js:11094
batchedUpdates$1                      @ react-dom.development.js:21893
notify                                @ Subscription.js:19
notifyNestedSubs                      @ Subscription.js:92
handleChangeWrapper                   @ Subscription.js:97
dispatch                              @ redux.js:222
e                                     @ VM64:1
(anonymous)                           @ effects.ts:11
(anonymous)                           @ write-middleware.ts:14
(anonymous)                           @ index.js:11
(anonymous)                           @ plugins.ts:538
(anonymous)                           @ plugins.ts:540
(anonymous)                           @ index.js:11
dispatch                              @ redux.js:638
effect                                @ ui.ts:60
(anonymous)                           @ effects.ts:13
(anonymous)                           @ write-middleware.ts:14
(anonymous)                           @ index.js:11
(anonymous)                           @ plugins.ts:538
(anonymous)                           @ plugins.ts:540
(anonymous)                           @ index.js:11
dispatch                              @ redux.js:638
(anonymous)                           @ ui.ts:54
(anonymous)                           @ index.js:8
dispatch                              @ VM64:1
(anonymous)                           @ index.tsx:162
emit                                  @ events.js:210
(anonymous)                           @ rpc.ts:31
emit                                  @ events.js:210
onMessage                             @ init.ts:50

@gaearon apprécie la réponse rapide. Je vais trouver un moyen de créer un exemple dans CodeSandbox (c'est difficile), mais en attendant, c'est ma trace de pile complète

la ligne qui pointe vers mon crochet personnalisé est la suivante : https://gist.github.com/suhanw/bcc2688bba131df8301dae073977654f#file -stack-trace-L144

ce serait génial si vous pouviez jeter un œil et me faire savoir s'il y a quelque chose dans la trace de la pile avant/après mon crochet personnalisé que je devrais étudier plus avant. Merci!

@LabhanshAgrawal Dans votre pile, UNSAFE_componentWillReceiveProps appelle quelque fitResize qui envoie une action Redux, qui à son tour met à jour un tas de composants. D'où le problème. Alors oui, changer cela en componentDidUpdate fonctionne.

@suhanw Dans votre pile, quelque chose appelé ModuleImpressionTracker semble envoyer une action Redux lors d'un constructeur. Les constructeurs ne devraient pas avoir d'effets secondaires. Je pense que c'est la cause du problème, pas votre crochet.

Je vois, donc j'en retiens que UNSAFE_componentWillReceiveProps est compté comme rendu mais pas componentDidUpdate .
Pouvez-vous préciser un peu qu'il s'agit d'un problème avec les composants fonctionnels et les crochets faisant setState, je n'ai pas pu le comprendre clairement à partir de la discussion ci-dessus.
Excusez-moi si la question est un peu idiote ou si ma conclusion est fausse, je suis un peu nouveau dans ce domaine.

@LabhanshAgrawal

Pouvez-vous préciser un peu qu'il s'agit d'un problème avec les composants fonctionnels et les crochets faisant setState, je n'ai pas pu le comprendre clairement à partir de la discussion ci-dessus.

Honnêtement, je ne suis pas sûr de moi à cause de tous les trucs Redux au milieu. C'est assez déroutant en raison de la façon dont React Redux est implémenté. Ce serait bien si quelqu'un pouvait obtenir une reproduction claire qui implique React seul mais utilise des composants de classe.

Il semble toujours qu'il y ait beaucoup de traces de pile collées, et peu de reproductions réelles du problème réel, quel que soit le type.

Je suppose que celui de urql est destiné à @gaearon, donc ce qui se passe est :

  • Nous avons notre <Todos /> monté, qui récupère les données et les rend
  • Le précédent a mis en place un flux connecté au urqlClient
  • Nous rendons notre deuxième <Todos /> cela produira la même combinaison requête + variables donc actualisera le résultat pour <Todos /> de la première étape.
  • use-subscription est déclenché pour les deux.

Repro - Appuyez sur "ouvrir" en haut lorsque la première requête est rendue.

Nous pourrions mettre en file d'attente les mises à jour, mais tant que nous ne faisons pas top-down rendus

EDIT : nous avons peut-être trouvé une solution pour le cas d'urql en ne déclenchant pas la mise à jour de tous les abonnés pendant le getCurrentValue d'un use-subscription

https://github.com/FormidableLabs/urql/commit/3a597dd92587ef852c18139e9781e853f763e930

OK, donc en approfondissant cela, je pense que nous mettons en garde dans plus de cas (par exemple pour les classes) que nous ne l'avions prévu à l'origine. Nous allons étudier la possibilité de faire taire certains d'entre eux.

@JoviDeCroock Cet exemple n'est pas très utile car je n'ai aucune idée de ce que fait urql . :-) Si vous souhaitez des commentaires sur un modèle, pourriez-vous préparer un bac à sable démontrant ce modèle isolément ?

@JoviDeCroock Oui, getCurrentValue n'est certainement pas destiné à avoir des effets secondaires. Nous pensions que ce nom était assez explicite à ce sujet.

J'ai eu un problème où je recevais cet avertissement lors de l'envoi d'une action de redux dans la portée racine d'un crochet personnalisé.

function useCustomHook() {
   const dispatch = useDispatch()
   const value = useSomeOtherHook()
   dispatch(action(value))
}

J'ai corrigé ce problème en enveloppant l'envoi dans un useEffect .

@Glinkis Cela ressemble

@gaearon oui, le problème que nous essayions de résoudre est mieux expliqué ici et semble assez courant.

@Glinkis Cela ressemble

J'ai besoin de garder mon état de redux synchronisé avec les identifiants de mon itinéraire, j'envoie donc cette mise à jour lorsque mon itinéraire change.

Je sais que cela peut être sous-optimal, mais je n'ai trouvé aucun autre moyen d'accéder aux données de routage à l'intérieur de mes sélecteurs.

@Glinkis D'où

@JoviDeCroock Je pense que notre dernière recommandation pour ce modèle est une passe de collecte des ordures planifiée personnalisée.

@Glinkis D'où

Je ne sais pas si cela appartient à cette discussion, mais c'est mon crochet.

export function useOpenFolder() {
  const dispatch = useDispatch()
  const match = useRouteMatch('/:workspace/(super|settings)?/:type?/:id?/(item)?/:item?')
  const { id, item } = match?.params || {}

  useEffect(() => {
    dispatch(
      openFolder({
        id: id || '',
        item: item || '',
      })
    )
  }, [dispatch, item, id])
}

J'utilise plus tard cet état pour des sélecteurs tels que :

export const getActiveItem = createSelector(
  [getActiveFolderItem, getItems],
  (activeItem, items) => items.all[activeItem]
)

@Glinkis Ouais, useRouteMatch dans le composant parent, de transmettre l'ID en tant qu'accessoire, puis de lire les accessoires dans le sélecteur comme vous le feriez normalement. (Je ne sais pas vraiment comment cela se fait dans Redux ces jours-ci, mais il doit y avoir un moyen.)

Je vois, donc j'en retiens que UNSAFE_componentWillReceiveProps est compté comme rendu mais pas componentDidUpdate .

@LabhanshAgrawal C'est correct. Quelques explications générales ici :

Conceptuellement, React fonctionne en deux phases :

  • La phase de rendu détermine quels changements doivent être apportés par exemple au DOM. Au cours de cette phase, React appelle render puis compare le résultat au rendu précédent.
  • La phase de validation est lorsque React applique les modifications. (Dans le cas de React DOM, c'est à ce moment que React insère, met à jour et supprime des nœuds DOM.) React appelle également des cycles de vie comme componentDidMount et componentDidUpdate pendant cette phase.

La phase de validation est généralement très rapide, mais le rendu peut être lent. Pour cette raison, le mode concurrent à venir (qui n'est pas encore activé par défaut) divise le travail de rendu en morceaux, interrompant et reprenant le travail pour éviter de bloquer le navigateur. Cela signifie que React peut invoquer les cycles de vie de la phase de rendu plus d'une fois avant de s'engager, ou il peut les invoquer sans s'engager du tout (en raison d'une erreur ou d'une interruption de priorité plus élevée).

Les cycles de vie des phases de rendu incluent les méthodes de composant de classe suivantes :

  • constructor
  • componentWillMount (ou UNSAFE_componentWillMount )
  • componentWillReceiveProps (ou UNSAFE_componentWillReceiveProps )
  • componentWillUpdate (ou UNSAFE_componentWillUpdate )
  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • Fonctions de mise setState jour

Étant donné que les méthodes ci-dessus peuvent être appelées plusieurs fois, il est important qu'elles ne contiennent pas d'effets secondaires. Ignorer cette règle peut entraîner divers problèmes, notamment des fuites de mémoire et un état d'application non valide. Malheureusement, il peut être difficile de détecter ces problèmes car ils peuvent souvent être non déterministes .

OK, donc en approfondissant cela, je pense que nous mettons en garde dans plus de cas (par exemple pour les classes) que nous ne l'avions prévu à l'origine. Nous allons étudier la possibilité de faire taire certains d'entre eux.

Je suppose que même si c'est plus que prévu, à mon avis, c'est une bonne chose à avoir car cela aide à améliorer nos projets en utilisant des classes.

Ce message d'erreur explicite "Impossible de mettre à jour un composant depuis le corps de la fonction d'un autre composant"

Cela signifie exécuter en tant que fonction au lieu d'appeler un composant.

exemple comme ceci :

const App = () => {  
  const fetchRecords = () => { 
    return <div>Loading..</div>;
  };  
  return fetchRecords() // and not like <FetchRecords /> unless it is functional component.
};
export default App;

@rpateld Je ne pense pas que l'exemple que vous montrez soit lié à cet avertissement.

https://github.com/facebook/react/pull/18330 résoudra les cas que nous n'avions pas l'intention de commencer à tirer.

Je suis également confronté à ce problème avec react@experimental + react-redux + redux .
image

Le code ressemble à ceci :

import React, { Suspense } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { Redirect } from 'react-router-dom'
import PropTypes from 'prop-types'
import { userActions, cabinetActions, tokensActions } from '../../actions'
import { CircularProgress } from '@material-ui/core'
import { api } from './api'

const Cabinet = ({ resource }) => {
    resource.read()
    return <h1>cabinet</h1>
}

Cabinet.propTypes = {
    resource: PropTypes.shape({
        read: PropTypes.func
    })
}

const CabinetPage = ({
    failedToLoad,
    tokensRefreshFailed,
    logout,
    loadCabinet,
    clearTokens,
    clearCabinet
}) => {
    if (tokensRefreshFailed || failedToLoad) {
        clearTokens()
        clearCabinet()
        logout()
        return <Redirect to='/login' />
    }

    return (
        <Suspense fallback={<CircularProgress />}>
            <Cabinet resource={loadCabinet()} />
        </Suspense>
    )
}

CabinetPage.propTypes = {
    loadCabinet: PropTypes.func,
    failedToLoad: PropTypes.bool,
    tokensRefreshFailed: PropTypes.bool,
    logout: PropTypes.func,
    clearTokens: PropTypes.func,
    clearCabinet: PropTypes.func
}

const mapStateToProps = ({
    alert,
    tokens: { tokensRefreshFailed },
    cabinet: { failedToLoad }
}) => ({
    alert,
    tokensRefreshFailed,
    failedToLoad
})

const mapDispatchToProps = dispatch =>
    bindActionCreators(
        {
            cabinetLoad: cabinetActions.load,
            logout: userActions.logoutWithoutRedirect,
            loadCabinet: api.loadCabinet,
            clearCabinet: cabinetActions.clear,
            clearTokens: tokensActions.clear
        },
        dispatch
    )

export default connect(mapStateToProps, mapDispatchToProps)(CabinetPage)

loadCabinet() envoie une action asynchrone de rendu en trois phases comme le disent les documents concurrents, et renvoie un objet avec read() prop.
Cependant, je ne vois aucune mise à jour des parents ici.

@h0tw4t3r Vous

En ce qui concerne le mode concurrent, veuillez noter que Redux n'est actuellement pas compatible avec celui-ci en général. Donc, vous voudrez peut-être l'éviter si vous expérimentez avec CM.

Petite mise à jour sur ce fil

Nous allons bientôt publier un correctif de React qui corrige le déclenchement excessif de cet avertissement pour les classes. Donc, si vous rencontrez cela, envisagez d'attendre quelques jours, puis d'essayer 16.13.1 quand il sera sorti.

Si vous voulez continuer à chercher les causes, j'espère que https://github.com/facebook/react/issues/18178#issuecomment -595846312 explique comment.

Je trouve très étrange que la même logique lorsqu'elle est utilisée dans un composant de classe ne donne aucun avertissement alors que fonctionnel (hooks):

Composant fonctionnel (Hooks) :

import React, { Component } from "react"
import SortableTree from "react-sortable-tree"
import "react-sortable-tree/style.css"

const data = [
  {
    title: "Windows 10",
    subtitle: "running",
    children: [
      {
        title: "Ubuntu 12",
        subtitle: "halted",
        children: [
          {
            title: "Debian",
            subtitle: "gone"
          }
        ]
      },
      {
        title: "Centos 8",
        subtitle: "hardening"
      },
      {
        title: "Suse",
        subtitle: "license"
      }
    ]
  }
]

const nodeInfo = row => console.log(row)

export default class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      searchString: "",
      searchFocusIndex: 0,
      searchFoundCount: null,
      treeData: data
    }
  }

  render() {
    const { searchString, searchFocusIndex, searchFoundCount } = this.state

    const customSearchMethod = ({ node, searchQuery }) =>
      searchQuery &&
      ((node.title &&
        node.title.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1) ||
        (node.subtitle &&
          node.subtitle.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1))

    const selectPrevMatch = () =>
      this.setState({
        searchFocusIndex:
          searchFocusIndex !== null
            ? (searchFoundCount + searchFocusIndex - 1) % searchFoundCount
            : searchFoundCount - 1
      })

    const selectNextMatch = () =>
      this.setState({
        searchFocusIndex:
          searchFocusIndex !== null
            ? (searchFocusIndex + 1) % searchFoundCount
            : 0
      })

    return (
      <div>
        <h2>Find the needle!</h2>
        <form
          style={{ display: "inline-block" }}
          onSubmit={event => {
            event.preventDefault()
          }}
        >
          <input
            id="find-box"
            type="text"
            placeholder="Search..."
            style={{ fontSize: "1rem" }}
            value={searchString}
            onChange={event =>
              this.setState({ searchString: event.target.value })
            }
          />
          &nbsp;
          <button
            type="button"
            disabled={!searchFoundCount}
            onClick={selectPrevMatch}
          >
            &lt;
          </button>
          &nbsp;
          <button
            type="submit"
            disabled={!searchFoundCount}
            onClick={selectNextMatch}
          >
            &gt;
          </button>
          &nbsp;
          <span>
            &nbsp;
            {searchFoundCount > 0 ? searchFocusIndex + 1 : 0}
            &nbsp;/&nbsp;
            {searchFoundCount || 0}
          </span>
        </form>

        <div style={{ height: 300 }}>
          <SortableTree
            treeData={this.state.treeData}
            onChange={treeData => this.setState({ treeData })}
            searchMethod={customSearchMethod}
            searchQuery={searchString}
            searchFocusOffset={searchFocusIndex}
            searchFinishCallback={matches =>
              this.setState({
                searchFoundCount: matches.length,
                searchFocusIndex:
                  matches.length > 0 ? searchFocusIndex % matches.length : 0
              })
            }
            generateNodeProps={row => {
              return {
                title: row.node.title,
                subtitle: (
                  <div style={{ lineHeight: "2em" }}>{row.node.subtitle}</div>
                ),
                buttons: [
                  <button
                    type="button"
                    className="btn btn-outline-success"
                    style={{
                      verticalAlign: "middle"
                    }}
                    onClick={() => nodeInfo(row)}
                  >
                    ℹ
                  </button>
                ]
              }
            }}
          />
        </div>
      </div>
    )
  }
}

image

Composante de classe :

import React from "react";
import SortableTree from "react-sortable-tree";
import "react-sortable-tree/style.css";

const data = [
  {
    title: "Windows 10",
    subtitle: "running",
    children: [
      {
        title: "Ubuntu 12",
        subtitle: "halted",
        children: [
          {
            title: "Debian",
            subtitle: "gone"
          }
        ]
      },
      {
        title: "Centos 8",
        subtitle: "hardening"
      },
      {
        title: "Suse",
        subtitle: "license"
      }
    ]
  }
];

const nodeInfo = row => console.log(row);

export default class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      searchString: "",
      searchFocusIndex: 0,
      searchFoundCount: null,
      treeData: data
    };
  }

  render() {
    const { searchString, searchFocusIndex, searchFoundCount } = this.state;

    const customSearchMethod = ({ node, searchQuery }) =>
      searchQuery &&
      ((node.title &&
        node.title.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1) ||
        (node.subtitle &&
          node.subtitle.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1));

    const selectPrevMatch = () =>
      this.setState({
        searchFocusIndex:
          searchFocusIndex !== null
            ? (searchFoundCount + searchFocusIndex - 1) % searchFoundCount
            : searchFoundCount - 1
      });

    const selectNextMatch = () =>
      this.setState({
        searchFocusIndex:
          searchFocusIndex !== null
            ? (searchFocusIndex + 1) % searchFoundCount
            : 0
      });

    return (
      <div>
        <h2>Find the needle!</h2>
        <form
          style={{ display: "inline-block" }}
          onSubmit={event => {
            event.preventDefault();
          }}
        >
          <input
            id="find-box"
            type="text"
            placeholder="Search..."
            style={{ fontSize: "1rem" }}
            value={searchString}
            onChange={event =>
              this.setState({ searchString: event.target.value })
            }
          />
          &nbsp;
          <button
            type="button"
            disabled={!searchFoundCount}
            onClick={selectPrevMatch}
          >
            &lt;
          </button>
          &nbsp;
          <button
            type="submit"
            disabled={!searchFoundCount}
            onClick={selectNextMatch}
          >
            &gt;
          </button>
          &nbsp;
          <span>
            &nbsp;
            {searchFoundCount > 0 ? searchFocusIndex + 1 : 0}
            &nbsp;/&nbsp;
            {searchFoundCount || 0}
          </span>
        </form>

        <div style={{ height: 300 }}>
          <SortableTree
            treeData={this.state.treeData}
            onChange={treeData => this.setState({ treeData })}
            searchMethod={customSearchMethod}
            searchQuery={searchString}
            searchFocusOffset={searchFocusIndex}
            searchFinishCallback={matches =>
              this.setState({
                searchFoundCount: matches.length,
                searchFocusIndex:
                  matches.length > 0 ? searchFocusIndex % matches.length : 0
              })
            }
            generateNodeProps={row => {
              return {
                title: row.node.title,
                subtitle: (
                  <div style={{ lineHeight: "2em" }}>{row.node.subtitle}</div>
                ),
                buttons: [
                  <button
                    type="button"
                    className="btn btn-outline-success"
                    style={{
                      verticalAlign: "middle"
                    }}
                    onClick={() => nodeInfo(row)}
                  >
                    ℹ
                  </button>
                ]
              };
            }}
          />
        </div>
      </div>
    );
  }
}

@radulle Ce n'est pas un exemple très utile en soi. J'ai essayé de le mettre dans CodeSandbox mais cela ne fonctionne pas : https://codesandbox.io/s/clever-taussig-9xixs. Pouvez-vous préparer un exemple que nous pouvons essayer?

@gaearon Je voulais créer une codesandbox mais la dernière version de la bibliothèque a quelques problèmes avec elle. L'erreur n'est pas levée dans les anciennes versions. Pour le moment, il semble que la seule façon de le reproduire soit de le faire tourner dans Create React App localement :(

@radulle Quelle version puis-je essayer qui fonctionnerait sur CodeSandbox ?

@gaearon 2.6.2 fonctionne et renvoie l'erreur/l'avertissement avec cette configuration :
image
Donc pour la même configuration :
Composant fonctionnel : erreurs/avertissements
Composant de classe : pas d'erreurs/avertissements
Peut-être que j'ai raté quelque chose et qu'ils ne sont pas équivalents.

Oui, c'est l'un des cas auxquels j'ai fait référence dans https://github.com/facebook/react/issues/18178#issuecomment -600369392. Nous désactiverons l'avertissement dans ce cas. L'avertissement lui-même est légitime et comme vous le dites à juste titre, conceptuellement, c'est aussi un problème dans les classes. Cependant, l'écart n'a pas de sens, nous allons donc le désactiver dans les deux cas pour l'instant lorsqu'il provient d' une classe (ce qui est le cas, dans cet exemple).

Je pense qu'il existe un cas d'utilisation légitime pour déclencher des mises à jour d'état à partir de la fonction de rendu et non d'un effet, et c'est de préserver l'ordre d'exécution.

Pour illustrer avec un exemple pratique : dans notre application, nous avons un système particulier de gestion du fil d'Ariane.

  • Nous avons un contexte mondial qui contient tous les fils d'Ariane
  • Nous avons un crochet qui nous permet d'ajouter des fils d'Ariane à ce contexte, comme ceci :

    const addBreadcrumb = useAddBreadcrumb();
    addBreadcrumb(<Breadcrumb>{item.name}</Breadcrumb>, [item.name]);
    
  • Nous avons un composant qui lit les informations du contexte et affiche tous les fils d'Ariane. Ainsi, chaque fois que nous voulons afficher le fil d'Ariane, nous devons simplement l'appeler sans paramètre.

C'est très pratique, car nous n'avons pas à maintenir de structure de fil d'Ariane : cette structure est déclarée dans le code lui-même. Si nous voulons déplacer une route vers une autre partie de l'application, le système de fil d'Ariane continuera à fonctionner.

Donc, combiné avec react-router , nous pouvons faire quelque chose comme ceci :

// Main/index.tsx
import { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import Home from './Home';
import Movies from './Movies';

const Main = () => {
    const addBreadcrumb = useAddBreadcrumb();
    addBreadcrumb(<Breadcrumb to="/">Home</Breadcrumb>, []);

    return <Switch>
        <Route path="/movies">
            <Movies />
        </Route>
        <Route path="/" />
            <Home />
        </Route>
    </Switch>
}

// Movies/index.tsx
import { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import Detail from './Detail';
import Master from './Master';

const Movies = ({ url }) => {
    const addBreadcrumb = useAddBreadcrumb();
    addBreadcrumb(<Breadcrumb to={url}>Movies</Breadcrumb>, [url]);

    return <Switch>
        <Route path="/:id">
            <Detail />
        </Route>
        <Route path="/" />
            <Master />
        </Route>
    </Switch>
}

// Movies/Detail/index.tsx
import Breadcrumbs, { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import { useRouteMatch } from 'react-router-dom';

const MovieDetail = ({ url }) => {
    const addBreadcrumb = useAddBreadcrumb();
    const { params: { id } } = useRouteMatch<{ id: string; }>();
    const movie = useMovie(id);

    addBreadcrumb(
        <Breadcrumb to={url}>{movie?.name}</Breadcrumb>,
        [movie?.name, url]
    );

    return <div>
        <Breadcrumbs />
    </div>
}

Maintenant, si nous allons à /movies/gone-with-the-wind , notre fil d'Ariane ressemblera à :

Home > Movies > Gone with the wind

Maintenant, voici mon point : pour que cela fonctionne, nous avons besoin que l'ordre d'exécution soit garanti. Dans ce cas, l'ordre d'exécution est évident : d'abord Main rend, puis il rend ses enfants, qui incluent Movies , et enfin MovieDetail . Dans ce cas, l'appel addBreadcrumb sera exécuté dans le bon ordre.

Maintenant, le changelog indique ceci :

Dans les rares cas où vous souhaitez intentionnellement modifier l'état d'un autre composant à la suite du rendu, vous pouvez encapsuler l'appel setState dans useEffect.

C'est, en effet, l'un des rares cas où l'on souhaite intentionnellement changer l'état d'un autre composant. Cependant, si nous faisons cela, le journal des modifications suggère et encapsule le addBreadcrumb (qui au final est un setState glorifié) dans useEffect , l'ordre d'exécution n'est plus garanti. Les trois setStates seront exécutés une fois le rendu terminé, ce qui crée une condition de concurrence et casse notre système.

Je ne sais pas si ce système particulier est considéré ou non comme un anti-modèle, mais pour moi, cela a du sens et je n'ai pas trouvé d'alternative plus simple.

Donc, pour conclure, je salue ce nouvel avertissement, mais je pense que la solution optimale pour nous serait d'avoir un moyen de le supprimer. Peut-être qu'un deuxième paramètre facultatif à setState ferait l'affaire.

@MeLlamoPablo

S'appuyer sur des appels de rendu dans l'ordre des frères et sœurs ou dans l'ordre de rendu parent/enfant semble très fragile. React ne le garantit pas réellement. Les enfants peuvent (et vont) refaire le rendu sans leurs parents, ainsi que l'inverse. Si les enfants sont rendus avec un retard (par exemple, le fractionnement du code), ce code se brisera également. Ou si certains enfants sont insérés ou supprimés dynamiquement. Sans oublier que c'est assez mauvais en termes de performances car vous avez tellement de rendus en cascade.

Je sympathise avec le problème que vous essayez de résoudre - en effet, il n'y a pas de solution idiomatique dans React aujourd'hui. Nous avons quelques idées à ce sujet, mais une solution appropriée devrait être assez différente. En attendant, nous déconseillons fortement cette solution de contournement.

@gaearon , merci pour votre perspicacité. J'ai une question : l'ordre du tout premier rendu est-il garanti ? Parce que c'est tout ce dont nous avons besoin pour fonctionner correctement (une fois que nous connaissons l'ordre des fils d'Ariane, nous ne nous soucions pas de l'ordre des rendus suivants).

Il me semble logique que l'ordre du premier rendu soit garanti. Sinon, comment React saurait-il qu'un composant parent a des enfants ?

Concernant les performances des rendus en cascade, vous avez tout à fait raison. Je chercherai des moyens d'améliorer notre système.

@MeLlamoPablo

J'ai une question : l'ordre du tout premier rendu est-il garanti ? Parce que c'est tout ce dont nous avons besoin pour fonctionner correctement (une fois que nous connaissons l'ordre des fils d'Ariane, nous ne nous soucions pas de l'ordre des rendus suivants).

Pas fortement. Je pense que cela fonctionne principalement dans la version actuelle de React, mais cela pourrait bien changer à l'avenir. Même aujourd'hui, combiné à des fonctionnalités telles que lazy et Suspense ce n'est pas garanti.

Sinon, comment React saurait-il qu'un composant parent a des enfants ?

L'ordre des frères et sœurs n'est pas garanti. Pour l'ordre parent/enfant, vous avez raison, les parents doivent d' abord effectuer le rendu ; cependant, React peut avoir besoin de restituer à nouveau le parent avant qu'il n'atteigne un enfant, ou même après avoir rendu le premier enfant mais avant le second. Encore une fois, une fois que vous ajoutez des fonctionnalités telles que le fractionnement de code, vous perdez des garanties encore plus rapidement.

C'est fragile.

@gaearon , merci encore. C'est très apprécié.

Peut-être qu'il devrait y avoir une règle ESLint qui met en garde contre l'appel useState mutateurs

L'appel de setState de votre propre composant pendant le rendu est un modèle pris en charge (bien qu'il doive être utilisé avec parcimonie). C'est setState sur d' autres composants qui sont mauvais. Vous ne pouvez pas les détecter statiquement.

Cela pourrait théoriquement être fait en utilisant ts-eslint, en supposant qu'ils utilisent les bons types React en amont, mais oui, probablement plus d'efforts que cela n'en vaut la peine.

Je ne pense pas que cela puisse être fait sans une sorte de suivi des effets. Dès que vous avez une fonction au milieu, vous perdez l'information.

Je suis également confronté à ce problème avec react@experimental + react-redux + redux .
image

Le code ressemble à ceci :

import React, { Suspense } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { Redirect } from 'react-router-dom'
import PropTypes from 'prop-types'
import { userActions, cabinetActions, tokensActions } from '../../actions'
import { CircularProgress } from '@material-ui/core'
import { api } from './api'

const Cabinet = ({ resource }) => {
  resource.read()
  return <h1>cabinet</h1>
}

Cabinet.propTypes = {
  resource: PropTypes.shape({
      read: PropTypes.func
  })
}

const CabinetPage = ({
  failedToLoad,
  tokensRefreshFailed,
  logout,
  loadCabinet,
  clearTokens,
  clearCabinet
}) => {
  if (tokensRefreshFailed || failedToLoad) {
      clearTokens()
      clearCabinet()
      logout()
      return <Redirect to='/login' />
  }

  return (
      <Suspense fallback={<CircularProgress />}>
          <Cabinet resource={loadCabinet()} />
      </Suspense>
  )
}

CabinetPage.propTypes = {
  loadCabinet: PropTypes.func,
  failedToLoad: PropTypes.bool,
  tokensRefreshFailed: PropTypes.bool,
  logout: PropTypes.func,
  clearTokens: PropTypes.func,
  clearCabinet: PropTypes.func
}

const mapStateToProps = ({
  alert,
  tokens: { tokensRefreshFailed },
  cabinet: { failedToLoad }
}) => ({
  alert,
  tokensRefreshFailed,
  failedToLoad
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
      {
          cabinetLoad: cabinetActions.load,
          logout: userActions.logoutWithoutRedirect,
          loadCabinet: api.loadCabinet,
          clearCabinet: cabinetActions.clear,
          clearTokens: tokensActions.clear
      },
      dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(CabinetPage)

loadCabinet() envoie une action asynchrone de rendu en trois phases comme le disent les documents concurrents, et renvoie un objet avec read() prop.
Cependant, je ne vois aucune mise à jour des parents ici.

Pour toute autre personne ayant ce problème, je l'ai résolu en déplaçant la répartition de l'action redux vers un composant renvoyé. Voici à quoi cela ressemble maintenant :

const CabinetPage = ({
    alert,
    failedToLoad,
    tokensRefreshFailed,
    logout,
    loadCabinet,
    clearTokens,
    clearCabinet,
    clearAlert
}) => (
    <Suspense fallback={<MUIBackdropProgress />}>
        {alert.message && (failedToLoad || tokensRefreshFailed) ? (
            <MUIAlertDialog
                title={alert.message}
                text={errorText}
                onClose={() => {
                    clearAlert()
                    clearCabinet()
                    clearTokens()
                    logout()
                }}
            />
        ) : (
            <Cabinet resource={loadCabinet()} />
        )}
    </Suspense>
)

J'aime cet avertissement car il vous oblige à choisir les bons modèles de conception. Maintenant, tout fonctionne parfaitement !

Nous avons corrigé les cas où l'avertissement se déclenchait en 16.13.1. Les autres cas sont légitimes et doivent être corrigés.

@gaearon vient d'être mis à jour et l'erreur a disparu ! Merci les gars pour votre travail !

@gaearon merci. tu viens de me sauver la journée :-)

Bien que la mise à niveau n'ait pas résolu mon problème, elle m'a donné plus d'informations dans la console pour m'aider à trouver mon problème. Merci @gaearon !

Que se passe-t-il si vous envoyez une action qui fait que l'autre composant renvoie le même état que la dernière fois ? Est-ce considéré comme mauvais ? Je pense qu'il y aurait un court-circuit dans ce cas.

Puis-je simplement dire que cela alors que je comprends totalement la logique derrière cet avertissement ... cela ressemble presque à une trahison de ce que l'équipe React a dit à la communauté, car on a l'impression que l'équipe a enseigné ces vérités importantes sur la façon de coder Réagir:

1) gardez votre état aussi haut que nécessaire dans votre hiérarchie (pas plus haut), puis transmettez les données et les setters aux composants enfants

2) Les composants fonctionnels sont géniaux ! Oubliez ce bruit de classe, faites tout votre composant en une seule fonction !

Et maintenant, quand les gens suivent ces deux règles, et transmettent leurs paramètres d'état à leurs composants de fonction, et les appellent dans ces composants... à faire".

Rien de tout cela ne change quoi que ce soit sur les besoins techniques ici, et je ne dis pas que ce changement est faux ou mauvais ... Je pense juste qu'il y a un problème de messagerie, en ce sens que vous ne communiquez pas de bonnes règles claires (comme les deux Je viens de mentionner) pour le codage dans ce nouveau monde. Si vous voulez changer les règles qui nous concernent, je pense qu'il serait utile de le faire en expliquant d' abord les meilleures pratiques.

Donc, tout ce que je demande vraiment, c'est... Je pense que ce serait plus idéal si quelqu'un dans l'équipe écrivait quelque chose (comme un article) où il dit "Je sais que nous vous avons déjà donné ces deux règles : voici les nouvelles règles", puis ajoutez un lien vers ce que cet article à chaque endroit dans les docs/notes de version qui font référence à ce nouvel avertissement (ainsi tout le monde googler "WTF est-ce?" peut apprendre la bonne façon de coder React, dans le "nouveau monde").

@machineghost : Je pense que vous ne comprenez pas ce que le message met en garde.

Il n'y a rien de mal à passer des rappels aux enfants qui mettent à jour l'état des parents. Cela a toujours été bien.

Le problème est lorsqu'un composant met en file d'attente une mise à jour dans un autre composant, _pendant que le premier composant effectue le rendu_.

En d'autres termes, ne faites pas ceci :

function SomeChildComponent(props) {
    props.updateSomething();
    return <div />
}

Mais c'est bien :

function SomeChildComponent(props) {
    // or make a callback click handler and call it in there
    return <button onClick={props.updateSomething}>Click Me</button>
}

Et, comme Dan l'a souligné à plusieurs reprises, la mise en file d'attente d'une mise à jour dans le composant _same_ pendant le rendu convient également :

function SomeChildComponent(props) {
  const [number, setNumber] = useState(0);

  if(props.someValue > 10 && number < 5) {
    // queue an update while rendering, equivalent to getDerivedStateFromProps
    setNumber(42);
  }

  return <div>{number}</div>
}

D'accord, mais lorsque vous codez votre composant, vous ne pensez pas au timing de son parent. Cela fait partie de la beauté des composants React : l'encapsulation.

Donc, encore une fois, je ne dis pas du tout que le nouvel avertissement est mauvais, je dis avant que nous ayons deux règles que tout bon développeur React pourrait suivre. Maintenant, dans les conditions X, ces règles sortent de la fenêtre, mais uniquement sous X (où cela ressemble à X = "pendant que le composant parent est également mis à jour").

Je pense juste qu'il faut se concentrer davantage sur l'explication de cela et sur la façon d'éviter le problème, au lieu de simplement dire "c'est un problème maintenant!".

@machineghost : vous ne comprenez _vraiment_ pas ce que je dis ici.

Le timing parent/enfant n'est pas le problème.

La mise à jour de l'état de la file d'attente _dans d'autres composants tout en restituant un composant de fonction_ est le problème.

Par définition, il doit s'agir d'un parent/enfant (ou petit-enfant) : sinon, comment aurait-il pu transmettre l'auteur de l'état ?

Je ne dis pas que cela ne peut pas également être un problème dans d'autres relations de composants, mais je parle spécifiquement des personnes qui suivent les meilleures pratiques de React, transmettent les paramètres d'état, puis reçoivent cet avertissement.

C'est tout ce dont je parle, et tout ce que je dis, c'est "cela pourrait être mieux expliqué, en mettant davantage l'accent sur la façon de bien coder au lieu de simplement" voici une nouvelle erreur et voici ce que cela signifie "".

Horaire. Pas. Problème.

Un composant de fonction est autorisé à mettre en file d'attente une mise à jour d'état, lors du rendu, pour lui-même uniquement . Comme mon exemple l'a montré, cela agit comme l'équivalent de getDerivedStateFromProps .

Mettre en file d'attente une mise à jour pour _tout_ autre composant à partir du corps de rendu réel d'un composant de fonction est illégal.

C'est ce que vous dit cet avertissement.

Je ne sais pas comment expliquer cela plus clairement.

Le timing n'est pas le problème : pas le vôtre, pas le mien. Mon problème est la documentation, ou son absence.

Mais vous avez décidé de déclencher une guerre dans un fil de discussion avec un étranger sur Internet, au lieu d'écouter ce qu'ils disent et... Je n'ai aucune envie de continuer à m'engager avec vous.

Le fait est qu'aucune règle n'a changé. Cela a toujours été un mauvais modèle. Il vient juste d'être mis en surbrillance pour que vous sachiez que votre code est bogué.

Et littéralement, rien de ce que vous venez de dire n'est en désaccord avec tout ce que j'ai écrit. En fait, c'est presque comme si j'avais dit exactement la même chose depuis le début ... et tout ce que j'ai demandé pendant tout ce temps était une meilleure explication de ces mêmes règles, celles que vous dites n'ont pas changé (et bien sûr ils n'ont pas ... ce qui a changé et "créé un nouveau monde" était l'avertissement).

PS Vous semblez également ne pas réaliser l'ironie ici. Si je ne comprends rien, c'est que la documentation pourrait être améliorée. Me crier dessus à quel point je comprends mal les choses ne fait que renforcer ma position ; cela n'améliore pas comme par magie la documentation.

Salut les gens, calmons-nous un peu. ??

@markerikson Je vous remercie de vous

@machineghost Merci d'avoir exprimé vos préoccupations. Je sais que c'est ennuyeux lorsque de nouveaux avertissements apparaissent pour des modèles qui auraient pu sembler inoffensifs auparavant.

Je suis d'accord que cet avertissement nécessite un certain contexte préalable. Essentiellement, vous deviez savoir deux choses de l'ère de la classe :

  • Que vous ne devriez pas définir l'état pendant le rendu. Les classes ont toujours prévenu à ce sujet.

  • Ce corps de composant de fonction est essentiellement la même chose que la méthode de rendu de composant de classe.

C'est en effet notre omission que setState sur un autre composant pendant la fonction body du composant n'a pas averti auparavant. Vous pouvez en déduire que c'est un mauvais schéma à partir des deux points ci-dessus, mais il est juste de dire que l'on ne peut pas s'en rendre compte. Nous sommes désolés pour le désagrément.

Si vous pensez qu'il y a un endroit particulier dans la doc où cela devrait être mentionné, veuillez soulever un problème sur le référentiel docs. Nous prévoyons une réécriture de la documentation basée sur les Hooks, c'est donc quelque chose que nous pouvons garder à l'esprit. Merci!

Je ne veux en aucun cas mettre quelqu'un de mal à propos de quoi que ce soit, et je refuse d'accepter vos excuses ;) Les crochets sont du génie, et vous êtes tous des génies pour les avoir inventés. Et tout ingénieur qui reproche à un autre ingénieur de ne pas avoir parfaitement imaginé chaque résultat est... un imbécile.

Tout ce que j'ai essayé de communiquer, c'est qu'actuellement, lorsque j'ai reçu cet avertissement, j'ai fait ce que tout le monde fait : je l'ai googlé. J'ai ensuite trouvé une page qui disait "nous avons ce nouvel avertissement".

Je pense juste que cela aurait été mieux (et pourrait encore être mieux) s'il y avait eu (peut être) un lien dans cette annonce, ou des endroits similaires que quelqu'un pourrait trouver en cherchant sur Google, vers une "discussion de plus haut niveau" de "voici pourquoi nous avons introduit cette erreur et voici comment vous pouvez être un développeur React génial et suivre quelques directives de base pour ne jamais la rencontrer vous-même. "

Mais encore une fois, les crochets sont géniaux, l'équipe React est géniale, et même ce nouvel avertissement est génial (je suis sûr qu'il bat l'enfer de découvrir l'erreur contre laquelle il essaie de se protéger). Si quelqu'un doit des excuses à quelqu'un, c'est moi pour ne pas avoir dirigé cela.

Bien sûr, pas de rancune. La réponse à « pourquoi » n'est pas plus complexe que « si un composant déclenche des mises à jour sur d'autres composants lors du rendu, il devient très difficile de tracer le flux de données de votre application car il ne va plus de haut en bas ». Donc, si vous faites cela, vous gaspillez en quelque sorte les avantages de React.

Encore une fois, pour clarifier, ce n'est pas nouveau en soi - les classes ont toujours le même avertissement. Nous l'avons manqué avec Hooks et rectifions l'erreur. Je suppose que la façon dont vous le résolvez dépend du cas - nous ne pouvons donc pas vous donner d'instructions exactes - mais heureux de vous aider si vous partagez un exemple avec lequel vous avez du mal. En général, vous le corrigeriez de la même manière que vous corrigeriez l'avertissement de classe correspondant qui a toujours existé.

J'espère que ça aide un peu !

J'ajouterai mes deux cents à cette discussion et je suis d'accord avec

Le cas et le point étant ComponentDidMount et Unmount, on nous dit d'abord d'utiliser des composants de fonction, puis d'utiliser useEffect avec un tableau vide, puis on nous dit que ce n'est pas bon, maintenant nous avons ce désordre de message d'erreur. Je ne sais pas, j'apprécie tout le travail acharné pour réagir, mais nous avons vraiment besoin de plus d'efforts pour la documentation et les meilleures pratiques.

Je suis dans le train des fonctions depuis si longtemps (en essayant d'éviter les classes avec Recompose et autres, même avant les hooks) que je ne me souviens même pas de ces avertissements de classe.

Et bien que j'apprécie votre réponse, j'espérais principalement des "règles empiriques", des lignes directrices, les meilleures pratiques, etc. Des trucs comme "gardez votre état aussi haut que nécessaire pour couvrir tous les composants qui l'utilisent, mais pas plus haut " ou "passer les paramètres d'état aux composants enfants en utilisant l'inversion du modèle de contrôle".

Peut-être qu'il n'y en a tout simplement pas ici, mais peut-être quelque chose comme "si le composant fonctionnel A change d'état, il ne devrait pas rendre le composant enfant B auquel il passe un paramètre d'état (il devrait retourner tout de suite ou quelque chose), car alors si le le composant enfant s'affiche et change d'état, vous aurez des problèmes".

Ou peut-être qu'il est tard dimanche, j'ai travaillé toute la journée sur un projet personnel, et mon cerveau est tout simplement trop frit et transforme quelque chose de simple en quelque chose de difficile. Quoi qu'il en soit, je posterai un retour si j'ai d'autres suggestions de directives, mais sinon, je ne veux certainement pas que quelqu'un d'autre passe son dimanche soir là-dessus.

Merci encore quand même !

Je pense que nous arrivons au point où ce fil a dépassé son utilité.

Le cas et le point étant ComponentDidMount et Unmount, on nous dit d'abord d'utiliser des composants de fonction, puis d'utiliser useEffect avec un tableau vide, puis on nous dit que ce n'est pas bon, maintenant nous avons ce désordre de message d'erreur.

Je suis désolé que notre documentation ne vous ait pas aidé, mais il est très difficile de dire quels problèmes spécifiques vous avez rencontrés. C'est malheureusement très vague et c'est une distorsion de ce que nous avons essayé de dire. Comme un jeu de téléphone cassé. Si vous rencontrez un problème spécifique, veuillez déposer un nouveau problème et essayer de le décrire plus en détail. Nous essaierons de vous aider si vous pouvez être plus précis.

Et bien que j'apprécie votre réponse, j'espérais principalement des "règles empiriques", des lignes directrices, des bonnes pratiques, etc.

La règle d'or a toujours été de « ne pas effectuer d'effets secondaires lors du rendu ». Considérez le rendu comme un calcul pur. Les effets secondaires vont à un endroit différent (méthodes de cycle de vie dans les classes ou useEffect dans les composants de fonction). Il n'y a pas grand-chose de plus.

"si le composant fonctionnel A change d'état, il ne devrait pas rendre le composant enfant B auquel il passe un paramètre d'état (il devrait retourner tout de suite ou quelque chose), car alors si le composant enfant est rendu et change d'état, vous aurez des problèmes".

Je pense qu'il y a encore un malentendu ici. Il est parfaitement normal de passer des paramètres d'état à un composant enfant. A toujours été bien, et le sera toujours.

Le problème est de les appeler lors du rendu . Cela devrait généralement être complètement inutile. Il m'est difficile de deviner pourquoi vous le faites sans un exemple concret. Il est donc difficile d'aider.

Le thème général de ces deux conversations est que nous tournons en rond. La discussion est devenue méta, et au lieu de parler de cas spécifiques, nous discutons de vagues généralités. Il est probable que nous nous comprenions mal, mais le manque d'exemples concrets rend ce malentendu impossible à résoudre.

Pour cette raison, je vais verrouiller ce fil. J'apprécie beaucoup la contribution de tout le monde ici, et nous aimerions en savoir plus si vous avez du mal à corriger cet avertissement. La façon d'obtenir de l'aide est de déposer un problème avec un exemple de reproduction minimal. Ensuite, nous pourrons discuter de votre problème concret et vous aider à trouver une solution. Cela sera plus productif pour toutes les personnes impliquées et évitera également d'envoyer des e-mails à des dizaines de personnes qui ont déjà commenté ce fil et se sont finalement inscrites. Merci!

En tant que petite mise à jour (désolé d'avoir envoyé un ping à tout le monde), j'ai entendu que https://github.com/final-form/react-final-form/issues/751#issuecomment -606212893 a résolu un tas de ces erreurs pour les personnes qui l'utilisaient une bibliothèque.

Cette page vous a été utile?
0 / 5 - 0 notes