web-dev-qa-db-fra.com

Réagir: perdre des valeurs de référence

J'utilise deux composants et j'utilise ce modèle: le composant enfant doit rester isolé autant qu'il le peut - il gère sa propre erreur de validation. Le composant parent doit vérifier les erreurs qui ont des dépendances entre les enfants. Donc, dans mon cas: champ password et champ password confirmation.

Voici mon code:

a) Inscription (parent)

Définition de l'état initial.

 constructor() {
     super();

     this.state = {
         isPasswordMatching: false
     };
 }

Dans la méthode render(), je génère mon composant enfant. Par le biais d'un accessoire appelé callback, je propage la méthode isPasswordMatching() en liant le this du parent. Le but est que cette méthode puisse être appelée dans le composant enfant.

<TextInput
    id={'password'}
    ref={(ref) => this.password = ref}
    callback={this.isPasswordMatching.bind(this)}
    // some other unimportant props
/>

<TextInput
    id={'passwordConfirm'}
    ref={(ref) => this.passwordConfirm = ref}
    ...

isPasswordMatching() la méthode vérifie si les mots de passe correspondent (via les références this.password et this.passwordConfirm), puis met à jour l'état. Veuillez noter que cette méthode est appelée à l'intérieur de child (password ou passwordConfirm).

isPasswordMatching() {
    this.setState({
        isPasswordMatching: this.password.state.value === this.passwordConfirm.state.value
    });
}

b) TextInput (enfant)

Définition de l'état initial.

constructor() {
    super();

    this.state = {
        value: '',
        isValid: false
    };
}

Au flou, la validation est effectuée et l'état est mis à jour.

onBlur(event) {

    // doing validation and preparing error messages

    this.setState({
        value: value,
        isValid: this.error === null
    });
}

Dernier. Un accessoire de rappel est appelé.

componentDidUpdate(prevProps) {
    if (prevProps.id === 'password' || prevProps.id === 'passwordConfirm') {
        prevProps.callback();
    }
}

Problème

D'une certaine manière, mes références sont perdues. Scénario:

  1. Le composant parent est rendu
  2. Les composants enfants sont rendus
  3. J'entre dans un des champs de saisie et je sors (cela appelle la méthode onBlur()) - l'état est mis à jour, le composant enfant est rendu
  4. componentDidUpdate() est invoquée et prevProp.callback() également
  5. Lorsque je passe à la méthode isPasswordMatching(), je génère this.password Et this.passwordConfirm - ce sont des objets avec des valeurs de référence attendues. La mise à jour de l'état du parent - le composant est rendu.
  6. Ensuite, tous les enfants sont rendus, les composants sont mis à jour, le rappel est appelé mais cette fois this.password Et this.passwordConfirm Sont null.

Je ne sais pas pourquoi les références sont un peu perdues. Dois-je faire quelque chose différemment? Merci d'avance.

16
be-codified

Voir la réagissez ici , avec des avertissements importants et vous conseille quand utiliser ou ne pas utiliser les références.

Notez que lorsque le composant référencé est démonté et chaque fois que la référence change, l'ancienne référence sera appelée avec null comme argument. Cela empêche les fuites de mémoire dans le cas où l'instance est stockée, comme dans le deuxième exemple. Notez également que lors de l'écriture de références avec des expressions de fonction en ligne comme dans les exemples ici, React voit un objet fonction différent à chaque fois, donc à chaque mise à jour, ref sera appelé avec null immédiatement avant d'être appelé avec le instance de composant.

15
Galeel Bhasha

Je ne sais pas si cela répond à la question de @ be-codified pour non, mais j'ai trouvé cela rencontrant un problème similaire. Dans mon cas, il s'est avéré que c'était dû à l'utilisation d'un composant fonctionnel.

https://reactjs.org/docs/refs-and-the-dom.html#refs-and-functional-components

Références et composants fonctionnels Vous ne pouvez pas utiliser l'attribut ref sur les composants fonctionnels car ils ne le font pas. Vous devez convertir le composant en classe si vous avez besoin d'une référence, tout comme vous le faites lorsque vous avez besoin de méthodes de cycle de vie ou d'un état.
Vous pouvez cependant utiliser l'attribut ref à l'intérieur d'un composant fonctionnel tant que vous faites référence à un élément DOM ou à un composant de classe

La documentation explique ce que vous devez faire pour résoudre le problème si vous avez le contrôle du composant que vous essayez de rendre.

Cependant dans mon cas, le composant provenait d'une bibliothèque tierce. Donc, simplement envelopper le composant a bien fonctionné.

Fonctionne

<div ref={element => this.elementName = element}>
    <FunctionalComponent />
</div>

Ne fonctionne pas
définit this.elementName sur null

<FunctionalComponent ref={element => this.elementName = element} />

J'espère que cela aidera quiconque à trouver cette question comme moi.

5
mawburn