Comment passer des données du composant enfant à son parent dans ReactJS?

213

J'essaie d'envoyer des données d'un composant enfant à son parent comme suit:

const ParentComponent = React.createClass({
    getInitialState() {
        return {
            language: '',
        };
    },
    handleLanguageCode: function(langValue) {
        this.setState({language: langValue});
    },

    render() {
         return (
                <div className="col-sm-9" >
                    <SelectLanguage onSelectLanguage={this.handleLanguage}/> 
                </div>
        );
});

et voici le composant enfant:

export const SelectLanguage = React.createClass({
    getInitialState: function(){
        return{
            selectedCode: '',
            selectedLanguage: '',
        };
    },

    handleLangChange: function (e) {
        var lang = this.state.selectedLanguage;
        var code = this.state.selectedCode;
        this.props.onSelectLanguage({selectedLanguage: lang});   
        this.props.onSelectLanguage({selectedCode: code});           
    },

    render() {
        var json = require("json!../languages.json");
        var jsonArray = json.languages;
        return (
            <div >
                <DropdownList ref='dropdown'
                    data={jsonArray} 
                    value={this.state.selectedLanguage}
                    caseSensitive={false} 
                    minLength={3}
                    filter='contains'
                    onChange={this.handleLangChange} />
            </div>            
        );
    }
});

Ce dont j'ai besoin, c'est d'obtenir la valeur sélectionnée par utilisateur dans le composant parent. Je reçois cette erreur:

Uncaught TypeError: this.props.onSelectLanguage is not a function

Quelqu'un peut-il m'aider à trouver le problème?

PS Le composant enfant crée une liste déroulante à partir d'un fichier json, et j'ai besoin de la liste déroulante pour afficher les deux éléments du tableau json côte à côte (comme: "aaa, anglais" comme premier choix!)

{  
   "languages":[  
      [  
         "aaa",
         "english"
      ],
      [  
         "aab",
         "swedish"
      ],
}
Birish
la source
3
<SelectLanguage onSelectLanguage={this.handleLanguage*Code*}/> une faute de frappe.
Yury Tarabanko
@YuryTarabanko Merci, mais toujours la même erreur
Birish
@DavinTryon Comment dois-je l'ajouter? J'ai essayé comme ceci: handleLanguageCode: function(langValue) { this.setState({ language: langValue }).bind(this); },Mais cela renvoie une erreur:ncaught TypeError: Cannot read property 'bind' of undefined
Birish
2
@DavinTryon createClasslie automatiquement les méthodes sans réaction.
Yury Tarabanko
@OP pourriez-vous créer un violon illustrant le problème?
Yury Tarabanko

Réponses:

259

Cela devrait fonctionner. Lors de l'envoi de l'accessoire, vous l'envoyez en tant qu'objet, plutôt que de l'envoyer en tant que valeur ou de l'utiliser en tant qu'objet dans le composant parent. Deuxièmement, vous devez formater votre objet json pour qu'il contienne des paires nom-valeur et utiliser valueFieldet textFieldattribuerDropdownList

Réponse courte

Parent:

<div className="col-sm-9">
     <SelectLanguage onSelectLanguage={this.handleLanguage} /> 
</div>

Enfant:

handleLangChange = () => {
    var lang = this.dropdown.value;
    this.props.onSelectLanguage(lang);            
}

Détaillé:

ÉDITER:

Étant donné que React.createClass est obsolète à partir de la version 16.0, il est préférable d'aller de l'avant et de créer un composant React en l'étendant React.Component. Le passage des données de l'enfant au composant parent avec cette syntaxe ressemblera à

Parent

class ParentComponent extends React.Component {

    state = { language: '' }

    handleLanguage = (langValue) => {
        this.setState({language: langValue});
    }

    render() {
         return (
                <div className="col-sm-9">
                    <SelectLanguage onSelectLanguage={this.handleLanguage} /> 
                </div>
        )
     }
}

Enfant

var json = require("json!../languages.json");
var jsonArray = json.languages;

export class SelectLanguage extends React.Component {
    state = {
            selectedCode: '',
            selectedLanguage: jsonArray[0],
        }

    handleLangChange = () => {
        var lang = this.dropdown.value;
        this.props.onSelectLanguage(lang);            
    }

    render() {
        return (
            <div>
                <DropdownList ref={(ref) => this.dropdown = ref}
                    data={jsonArray} 
                    valueField='lang' textField='lang'
                    caseSensitive={false} 
                    minLength={3}
                    filter='contains'
                    onChange={this.handleLangChange} />
            </div>            
        );
    }
}

Utilisation de la createClasssyntaxe utilisée par l'OP dans sa réponse Parent

const ParentComponent = React.createClass({
    getInitialState() {
        return {
            language: '',
        };
    },

    handleLanguage: function(langValue) {
        this.setState({language: langValue});
    },

    render() {
         return (
                <div className="col-sm-9">
                    <SelectLanguage onSelectLanguage={this.handleLanguage} /> 
                </div>
        );
});

Enfant

var json = require("json!../languages.json");
var jsonArray = json.languages;

export const SelectLanguage = React.createClass({
    getInitialState: function() {
        return {
            selectedCode: '',
            selectedLanguage: jsonArray[0],
        };
    },

    handleLangChange: function () {
        var lang = this.refs.dropdown.value;
        this.props.onSelectLanguage(lang);            
    },

    render() {

        return (
            <div>
                <DropdownList ref='dropdown'
                    data={jsonArray} 
                    valueField='lang' textField='lang'
                    caseSensitive={false} 
                    minLength={3}
                    filter='contains'
                    onChange={this.handleLangChange} />
            </div>            
        );
    }
});

JSON:

{ 
"languages":[ 

    { 
    "code": "aaa", 
    "lang": "english" 
    }, 
    { 
    "code": "aab", 
    "lang": "Swedish" 
    }, 
  ] 
}
Shubham Khatri
la source
Merci Shubham, votre réponse a résolu le problème, mais elle n'affiche pas l'élément sélectionné dans la liste déroulante. Il est vide après ça: /
Birish
@Sarah Lors de la création de dropDownList, vous avez affecté sa valeur à this.state.selectedLanguage et qui n'est initialisée à aucune valeur. C'est peut-être le problème. Quel composant DropdownList utilisez-vous. Si je sais, je peux peut-être y travailler pour résoudre le problème.
Shubham Khatri
Vous avez raison. Le this.state.selectedLanguagesemble être toujours nul: / J'utilise DropdownList dereact-widgets
Birish
@Sarah J'ai apporté une petite modification au code, y compris la liaison de la valeur à la fonction onChange et la définition d'une valeur d'état initial. Essayez ceci et dites-moi si cela fonctionne pour vous
Shubham Khatri
Renvoie une erreur: Uncaught ReferenceError: value is not defined. J'ai fait ce changement: onChange={this.handleLangChange.bind(this, this.value)}et aucune erreur ne revient, mais il n'affiche toujours pas la valeur sélectionnée :(
Birish
108

Pour passer des données du composant enfant au composant parent

Dans le composant parent:

getData(val){
    // do not forget to bind getData in constructor
    console.log(val);
}
render(){
 return(<Child sendData={this.getData}/>);
}

Dans le composant enfant:

demoMethod(){
   this.props.sendData(value);
 }
Manisha Tan
la source
15
N'oubliez pas this.getData = this.getData.bind(this);dans le constructeur, car vous pouvez obtenir this.setState n'est pas une fonction si vous voulez manipuler l'état dans getData.
Miro J.
12

J'ai trouvé l'approche comment obtenir des données du composant enfant chez les parents quand j'en ai besoin.

Parent:

class ParentComponent extends Component{
  onSubmit(data) {
    let mapPoint = this.getMapPoint();
  }

  render(){
    return (
      <form onSubmit={this.onSubmit.bind(this)}>
        <ChildComponent getCurrentPoint={getMapPoint => {this.getMapPoint = getMapPoint}} />
        <input type="submit" value="Submit" />
      </form>
    )
  }
}

Enfant:

class ChildComponent extends Component{
  constructor(props){
    super(props);

    if (props.getCurrentPoint){
      props.getCurrentPoint(this.getMapPoint.bind(this));
    }
  }

  getMapPoint(){
    return this.Point;
  }
}

Cet exemple montre comment passer la fonction du composant enfant au parent et utiliser cette fonction pour obtenir des données de l'enfant.

MrDuDuDu
la source
10

Considérant que les composants de la fonction React et l'utilisation des crochets deviennent de plus en plus populaires ces jours-ci, je vais donner un exemple simple de la façon de passer des données de l'enfant au composant parent

dans le composant de fonction parent, nous aurons:

import React, { useState, useEffect } from "react";

puis

const [childData, setChildData] = useState("");

et en passant setChildData (qui font un travail similaire à this.setState dans les composants de classe) à Child

return( <ChildComponent passChildData={setChildData} /> )

dans le composant enfant, nous obtenons d'abord les accessoires de réception

function ChildComponent(props){ return (...) }

vous pouvez alors transmettre des données comme si vous utilisiez une fonction de gestionnaire

const functionHandler = (data) => {

props.passChildData(data);

}
Shayan Moghadam
la source
3

La méthode React.createClass est obsolète dans la nouvelle version de React, vous pouvez le faire très simplement de la manière suivante, créez un composant fonctionnel et un autre composant de classe pour maintenir l'état:

Parent:

const ParentComp = () => {
  
  getLanguage = (language) => {
    console.log('Language in Parent Component: ', language);
  }
  
  <ChildComp onGetLanguage={getLanguage}
};

Enfant:

class ChildComp extends React.Component {
    state = {
      selectedLanguage: ''
    }
    
    handleLangChange = e => {
        const language = e.target.value;
        thi.setState({
          selectedLanguage = language;
        });
        this.props.onGetLanguage({language}); 
    }

    render() {
        const json = require("json!../languages.json");
        const jsonArray = json.languages;
        const selectedLanguage = this.state;
        return (
            <div >
                <DropdownList ref='dropdown'
                    data={jsonArray} 
                    value={tselectedLanguage}
                    caseSensitive={false} 
                    minLength={3}
                    filter='contains'
                    onChange={this.handleLangChange} />
            </div>            
        );
    }
};

Sania Khushbakht Jamil
la source
3
Juste une note ... vous devriez référencer la version spécifique de React au lieu de "la nouvelle version" pour pérenniser cette réponse.
steve-o
3

du composant enfant au composant parent comme ci-dessous

composant parent

class Parent extends React.Component {
   state = { message: "parent message" }
   callbackFunction = (childData) => {
       this.setState({message: childData})
   },
   render() {
        return (
            <div>
                 <Child parentCallback = {this.callbackFunction}/>
                 <p> {this.state.message} </p>
            </div>
        );
   }
}

composant enfant

class Child extends React.Component{
    sendBackData = () => {
         this.props.parentCallback("child message");
    },
    render() { 
       <button onClick={sendBackData}>click me to send back</button>
    }
};

J'espère que ce travail

Manoj Rana
la source
2

dans le React v16.8+composant fonction, vous pouvez utiliser useState()pour créer un état de fonction qui vous permet de mettre à jour l'état parent, puis de le transmettre à l'enfant en tant qu'attribut d'accessoires, puis à l'intérieur du composant enfant, vous pouvez déclencher la fonction d'état parent, ce qui suit est un extrait de travail :

const { useState , useEffect } = React;

function Timer({ setParentCounter }) {
  const [counter, setCounter] = React.useState(0);

  useEffect(() => {
    let countersystem;
    countersystem = setTimeout(() => setCounter(counter + 1), 1000);

    return () => {
      clearTimeout(countersystem);
    };
  }, [counter]);

  return (
    <div className="App">
      <button
        onClick={() => {
          setParentCounter(counter);
        }}
      >
        Set parent counter value
      </button>
      <hr />
      <div>Child Counter: {counter}</div>
    </div>
  );
}

function App() {
  const [parentCounter, setParentCounter] = useState(0);

  return (
    <div className="App">
      Parent Counter: {parentCounter}
      <hr />
      <Timer setParentCounter={setParentCounter} />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('react-root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>

RACINE
la source
1

Vous pouvez même éviter que la fonction du parent ne mette à jour l'état directement

Dans le composant parent:

render(){
 return(<Child sendData={ v => this.setState({item: v}) } />);
}

Dans le composant enfant:

demoMethod(){
   this.props.sendData(value);
}
Banzy
la source
0

L'idée est d'envoyer un rappel à l'enfant qui sera appelé pour restituer les données

Un exemple complet et minimal utilisant des fonctions:

L'application créera un enfant qui calculera un nombre aléatoire et le renverra directement au parent, ce qui donnera console.logle résultat

const Child = ({ handleRandom }) => {
  handleRandom(Math.random())

  return <span>child</span>
}
const App = () => <Child handleRandom={(num) => console.log(num)}/>
Fabien Sa
la source
0

Composant parent: -TimeModal

  handleTimeValue = (timeValue) => {
      this.setState({pouringDiff: timeValue});
  }

  <TimeSelection 
        prePourPreHours={prePourPreHours}
        setPourTime={this.setPourTime}
        isPrePour={isPrePour}
        isResident={isResident}
        isMilitaryFormatTime={isMilitaryFormatTime}
        communityDateTime={moment(communityDT).format("MM/DD/YYYY hh:mm A")}
        onSelectPouringTimeDiff={this.handleTimeValue}
     />

Remarque : - onSelectPouringTimeDiff = {this.handleTimeValue}

Dans le composant enfant, appelez les accessoires si nécessaire

 componentDidMount():void{
      // Todo use this as per your scenrio
       this.props.onSelectPouringTimeDiff(pouringDiff);  
  }
Keshav Gera
la source