web-dev-qa-db-fra.com

Appeler la méthode enfant du parent

J'ai deux composants.

  1. Composant parent 
  2. Composante enfant

J'essayais d'appeler la méthode de l'enfant de Parent, j'ai essayé de cette façon mais je n'ai pas pu obtenir de résultat

class Parent extends Component {
  render() {
    return (
      <Child>
        <button onClick={Child.getAlert()}>Click</button>
      </Child>
      );
    }
  }

class Child extends Component {
  getAlert() {
    alert('clicked');
  }

  render() {
    return (
      <h1 ref="hello">Hello</h1>
    );
  }
}

Existe-t-il un moyen d'appeler la méthode de l'enfant de la part du parent?

Remarque: les composants enfant et parent sont dans deux fichiers différents. 

232
Evo SL

Tout d’abord, laissez-moi vous dire que c’est généralement le non le moyen de faire les choses dans le pays React. Habituellement, ce que vous voulez faire est de transmettre la fonctionnalité aux enfants des accessoires, et de transmettre les notifications des enfants dans les événements.

Mais si vous devez exposer une méthode impérative sur un composant enfant, vous pouvez utiliser refs . Rappelez-vous qu'il s'agit d'une trappe d'évacuation et indique généralement qu'une meilleure conception est disponible.

Auparavant, les références n'étaient prises en charge que pour les composants basés sur des classes. Avec l'avènement de React Hooks , ce n'est plus le cas

Utilisation des crochets et des composants de fonction (>= [email protected])

import React, { forwardRef, useRef, useImperativeHandle } from 'react';

// We need to wrap component in `forwardRef` in order to gain
// access to the ref object that is assigned using the `ref` prop.
// This ref is passed as the second parameter to the function component.
const Child = forwardRef((props, ref) => {

  // The component instance will be extended
  // with whatever you return from the callback passed
  // as the second argument
  useImperativeHandle(ref, () => ({

    getAlert() {
      alert("getAlert from Child");
    }

  }));

  return <h1>Hi</h1>;
});

const Parent = () => {
  // In order to gain access to the child component instance,
  // you need to assign it to a `ref`, so we call `useRef()` to get one
  const childRef = useRef();

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={() => childRef.current.getAlert()}>Click</button>
    </div>
  );
};

Exemple de fonctionnement

La documentation pour useImperativeHandle() est ici :

useImperativeHandle personnalise la valeur d'instance exposée aux composants parents lors de l'utilisation de ref.

Utilisation des composants de classe

class Parent extends Component {
  constructor(props) {
    super(props);
    this.child = React.createRef();
  }

  onClick = () => {
    this.child.current.getAlert();
  };

  render() {
    return (
      <div>
        <Child ref={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert('getAlert from Child');
  }

  render() {
    return <h1>Hello</h1>;
  }
}

ReactDOM.render(<Parent />, document.getElementById('root'));

Exemple de fonctionnement

API héritée (<= [email protected])

Pour des raisons historiques, voici le style basé sur les rappels que vous utiliseriez avec les versions de React antérieures à 16.3:

const { Component } = React;
const { render } = ReactDOM;

class Parent extends Component {
  render() {
    return (
      <div>
        <Child ref={instance => { this.child = instance; }} />
        <button onClick={() => { this.child.getAlert(); }}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert('clicked');
  }

  render() {
    return (
      <h1>Hello</h1>
    );
  }
}


render(
  <Parent />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>

323
rossipedia

Vous pouvez utiliser un autre motif ici:

class Parent extends Component {
 render() {
  return (
    <div>
      <Child setClick={click => this.clickChild = click}/>
      <button onClick={() => this.clickChild()}>Click</button>
    </div>
  );
 }
}

class Child extends Component {
 constructor(props) {
    super(props);
    this.getAlert = this.getAlert.bind(this);
 }
 componentDidMount() {
    this.props.setClick(this.getAlert);
 }
 getAlert() {
    alert('clicked');
 }
 render() {
  return (
    <h1 ref="hello">Hello</h1>
  );
 }
}

Cela permet de définir la méthode clickChild du parent lorsque l'enfant est monté. De cette façon, lorsque vous cliquerez sur le bouton dans parent, il appellera clickChild qui appellera getAlert de l'enfant.

Cela fonctionne aussi si votre enfant est entouré de connect (), vous n'avez donc pas besoin du hack getWrappedInstance ().

Notez que vous ne pouvez pas utiliser onClick = {this.clickChild} dans parent car lorsque parent est rendu, l'enfant n'est pas monté, donc this.clickChild n'est pas encore affecté. Utiliser onClick = {() => this.clickChild ()} est acceptable car lorsque vous cliquez sur le bouton, this.clickChild doit déjà être attribué.

68
brickingup

https://facebook.github.io/react/tips/expose-component-functions.html pour plus de réponses, réf ici Méthodes d'appel sur les composants enfants React

En examinant les références du composant "raison", vous rompez l’encapsulation et vous empêche de le refactoriser sans un examen minutieux de tous les endroits où il a été utilisé. Pour cette raison, nous recommandons fortement de traiter les références comme des données privées à un composant, un peu comme dans l'état.

En général, les données doivent être transmises dans l'arbre via des accessoires. Il y a quelques exceptions à cela (comme appeler .focus () ou déclencher une animation ponctuelle qui ne "change" pas vraiment l'état), mais chaque fois que vous exposez une méthode appelée "set", les accessoires sont généralement utilisés. un meilleur choix. Essayez de faire en sorte que le composant d'entrée interne s'inquiète de sa taille et de son apparence afin qu'aucun de ses ancêtres ne le fasse.

22
Mike Tronic

Nous pouvons utiliser les arbitres d'une autre manière,

Nous allons créer un élément Parent, il rendra un composant <Child/>. Comme vous pouvez le voir, le composant qui sera rendu, vous devez ajouter l'attribut ref et lui donner un nom.
Ensuite, la fonction triggerChildAlert, située dans la classe parente, accédera à la propriété refs du contexte suivant (lorsque la fonction triggerChildAlert sera déclenchée, elle aura accès à la référence enfant et comportera toutes les fonctions de l'élément enfant). 

class Parent extends React.Component {
    triggerChildAlert(){
        this.refs.child.callChildMethod();
        // to get child parent returned  value-
        // this.value = this.refs.child.callChildMethod();
        // alert('Returned value- '+this.value);
    }

    render() {
        return (
            <div>
                {/* Note that you need to give a value to the ref parameter, in this case child*/}
                <Child ref="child" />
                <button onClick={this.triggerChildAlert}>Click</button>
            </div>
        );
    }
}  

Maintenant, le composant enfant, tel que théoriquement conçu précédemment, ressemblera à ceci: 

class Child extends React.Component {
    callChildMethod() {
        alert('Hello World');
        // to return some value
        // return this.state.someValue;
    }

    render() {
        return (
            <h1>Hello</h1>
        );
    }
}

Voici le source code-
L’espoir vous aidera!

4
S.Yadav

Si vous faites cela simplement parce que vous voulez que l'enfant fournisse à ses parents un trait réutilisable, vous pouvez envisager de le faire en utilisant render-props .

Cette technique bouleverse réellement la structure. La Child enveloppe maintenant le parent, alors je l'ai renommé en AlertTrait ci-dessous. J'ai gardé le nom Parent pour la continuité, bien que ce ne soit plus vraiment un parent.

// Use it like this:

  <AlertTrait renderComponent={Parent}/>


class AlertTrait extends Component {
  // You may need to bind this function, if it is stateful
  doAlert() {
    alert('clicked');
  }
  render() {
    return this.props.renderComponent(this.doAlert);
  }
}

class Parent extends Component {
  render() {
    return (
      <button onClick={this.props.doAlert}>Click</button>
    );
  }
}

Dans ce cas, AlertTrait fournit un ou plusieurs traits qu’il transmet comme élément de support quel que soit le composant qui lui a été attribué dans son accessoire renderComponent.

Le parent reçoit doAlert comme accessoire et peut l'appeler si nécessaire.

(Par souci de clarté, j’ai appelé la propriété renderComponent dans l’exemple ci-dessus. Mais dans les documents React liés ci-dessus, ils l’appellent simplement render.)

Le composant Trait peut rendre les éléments entourant le parent, dans sa fonction de rendu, mais il ne restitue rien à l'intérieur du parent. En réalité, il pourrait restituer des éléments à l'intérieur du parent s'il transmettait un autre accessoire (par exemple renderChild) au parent, que ce dernier pourrait ensuite utiliser lors de sa méthode de rendu.

C'est un peu différent de ce que le PO a demandé, mais certaines personnes pourraient se retrouver ici (comme nous) parce qu'elles voulaient créer un trait réutilisable et pensaient qu'un composant enfant était un bon moyen de le faire.

3
joeytwiddle

Vous pouvez effectuer une inversion d'héritage (consultez-la ici: https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e ). De cette façon, vous avez accès à une instance du composant que vous souhaitez encapsuler (vous pourrez ainsi accéder à ses fonctions)

0
szpada87

Je pense que le moyen le plus simple d'appeler des méthodes consiste à définir une requête sur le composant enfant. Ensuite, dès que l'enfant gère la demande, il appelle une méthode de rappel pour réinitialiser la demande.

Le mécanisme de réinitialisation est nécessaire pour pouvoir envoyer la même demande plusieurs fois l’une après l’autre.

Dans le composant parent

Dans la méthode de rendu du parent:

const { request } = this.state;
return (<Child request={request} onRequestHandled={()->resetRequest()}/>);

Le parent a besoin de 2 méthodes pour communiquer avec son enfant dans 2 directions.

sendRequest() {
  const request = { param: "value" };
  this.setState({ request });
}

resetRequest() {
  const request = null;
  this.setState({ request });
}

En composante enfant

L'enfant met à jour son état interne, en copiant la demande des accessoires.

constructor(props) {
  super(props);
  const { request } = props;
  this.state = { request };
}

static getDerivedStateFromProps(props, state) {
  const { request } = props;
  if (request !== state.request ) return { request };
  return null;
}

Enfin, il gère la demande et envoie la réinitialisation au parent:

componentDidMount() {
  const { request } = this.state;
  // todo handle request.

  const { onRequestHandled } = this.props;
  if (onRequestHandled != null) onRequestHandled();
}
0
bvdb

Vous pouvez y arriver facilement de cette manière

Pas-

  1. Créez une variable booléenne dans l'état de la classe parent. Mettez-le à jour lorsque vous souhaitez appeler une fonction.
  2. Créez une variable prop et assignez la variable booléenne.
  3. Depuis le composant enfant, accédez à cette variable à l'aide de props et exécutez la méthode de votre choix en utilisant une condition if.

    class Child extends Component {
       Method=()=>{
       --Your method body--
       }
       render() {
         return (
        //check whether the variable has been updated or not
          if(this.props.updateMethod){
            this.Method();
          }
         )
       }
    }
    
    class Parent extends Component {
    
    constructor(){
      this.state={
       callMethod:false
      }
    
    }
    render() {
       return (
    
         //update state according to your requirement
         this.setState({
            callMethod:true
         }}
         <Child updateMethod={this.state.callMethod}></Child>
        );
       }
    }
    
0
Kusal Kithmal