36 votes

Avertissement de React à propos de setState dans un composant non monté

J'obtiens cette erreur :

warning.js:33 Avertissement : Impossible d'appeler setState (ou forceUpdate) sur un composant non monté. composant non monté. Ce n'est pas une option, mais cela indique une fuite de mémoire dans votre application. Pour le corriger, annulez tous les abonnements et les tâches asynchrones asynchrones dans la méthode componentWillUnmount.

Mais je n'utilise pas de méthode componentWillUnMount.

J'utilise un HOC pour m'assurer que l'utilisateur est authentifié avant d'accéder à sa route /compte.

Voici l'itinéraire :

<StyleRoute props={this.props} path="/account" component= 
{RequireAuth(Account)} />

où RequireAuth est le HOC. Voici le HOC :

 import { withRouter } from 'react-router';

export default function RequireAuth(Component) {

  return class AuthenticatedComponent extends React.Component {

    componentWillMount() {
      this.checkAuth();
    }

    checkAuth() {
      if ( ! this.props.isAuthenticated) {
        this.props.history.push(`/`);
      }
    }

    render() {
      return this.props.isAuthenticated
        ? <Component { ...this.props } />
        : null;
    }

  }

  return withRouter(AuthenticatedComponent);
}

Le code fonctionne comme prévu, mais j'obtiens cette erreur lorsque /account est rendu. Comme vous pouvez le constater, il n'y a pas de méthode componentWillUnMount dans mon code direct. Je ne comprends vraiment pas pourquoi cet avertissement continue de s'afficher et toute information serait utile.


Mise à jour 5/23/18 :

Pour se débarrasser de l'erreur et avoir toujours des accessoires en bas, j'ai fait deux choses :

1) J'ai choisi d'avoir deux fonctions d'ordre supérieur dans le composant App parent au lieu d'utiliser le HOC. L'une des fonctions d'ordre supérieur sert à passer les props et l'autre à vérifier l'authentification. J'avais des difficultés à passer des props autres que l'historique du navigateur, d'où la fonction renderProps ci-dessous.

renderProps = (Component, props) => {
  return (
      <Component {...props} />
    );
}

checkAuth = (Component, props) => {
    if (props.isAuthenticated) {
        return <Component {...props} />
    }
    if (!props.isAuthenticated) {
        return <Redirect to='/' />
    }
}

2) Pour les utiliser, j'ai dû utiliser le rendu dans ma route, par opposition au composant.

//I could pass props doing this, sending them through the above functions
<Route exact path="/sitter-dashboard" render={ () => this.checkAuth(SitterDashboard, this.props) } />
<Route exact path={"/account/user"} render={() => this.renderProps(User, this.props)} />

//I couldn't pass props doing this
<Route {...this.props} exact path="/messages" component={Messages} />

Voici la documentation sur le routeur et le composant comme méthode de rendu de la route : https://reacttraining.com/react-router/web/api/Route/route-render-methods

Voici également une bonne explication sur Stack Overflow

Enfin, j'ai utilisé ce code de la documentation de React Router 4 comme modèle pour ce que j'ai fait ci-dessus. Je suis sûr que le code ci-dessous est plus propre, mais je suis encore en train d'apprendre et ce que j'ai fait a un peu plus de sens pour moi.

const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
  {...rest}
  render={props =>
  fakeAuth.isAuthenticated ? (
       <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);

1 votes

Pouvez-vous essayer la même chose en remplaçant ComponentWillMount par ComponentDidMount ?

0 votes

Je l'ai fait, mais une erreur s'est produite, car il faut savoir s'ils sont authentifiés avant que le composant ne soit rendu.

0 votes

Ok, dans ce cas vous pouvez enlever le history.push de là et mettre un drapeau pour montrer que c'est non authentifié et retourner <Redirect path="/"> dans render() dans les cas non authentifiés. Le histoty.push va essayer de démonter des composants qui ne sont pas montés, d'où l'erreur.

14voto

Lucas Milotich Points 135

J'ai eu la même erreur il y a un certain temps et elle était générée par un composant qui utilisait la balise ref, et il y avait une certaine manipulation manuelle.

Une bonne pratique pour voir ce genre d'erreurs est de dessiner le flux de votre application et de voir quand vous appelez setState .

Une autre chose que je changerais, si j'étais vous. componentDidMount au lieu de componentWillMount pour vérifier certaines données. Prenez en compte le fait que FB a déprécié cette fonctionnalité.

Ce cycle de vie s'appelait auparavant componentWillMount. Ce nom continuera à fonctionner jusqu'à la version 17. Utilisez le codemod rename-unsafe-lifecycles pour mettre automatiquement à jour vos composants.

Documentation sur les composants Reactjs

8voto

Divyanshu Rawat Points 383

J'ai eu un problème similaire, mais j'ai trouvé la raison derrière le même, donc voici le bout de code où je rencontrais cette erreur.

Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

Cause :

   this.setState({ showLoader: true });
    const { username } = this.state;
    const URL = `https://api.github.com/users/${username}`;
    try {
      const { data } = await axios(URL);
      this.props.apiData(data);
      this.props.history.push("profile");
    } catch (e) {
      console.error(e);
    }
    this.setState({ showLoader: false });

Comme vous pouvez le voir dans l'extrait de code, je faisais

this.props.history.push("profile");

avant de définir l'état.

this.setState({ showLoader: false });

Et puis err semble être légitime dans ce cas, car je redirigeais vers un composant différent, puis je réglais l'état du composant précédent.

Solution :

En plaçant

this.setState({ showLoader: false });

au-dessus de la this.props.history.push("profile"); a résolu le problème.

J'espère que cela vous aidera.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X