Come passare i dati dal componente figlio al suo genitore in ReactJS?


213

Sto provando a inviare dati da un componente figlio al suo genitore come segue:

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>
        );
});

ed ecco il componente figlio:

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>            
        );
    }
});

Ciò di cui ho bisogno è ottenere il valore selezionato dall'utente nel componente padre. Ricevo questo errore:

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

Qualcuno può aiutarmi a trovare il problema?

PS Il componente figlio sta creando un menu a discesa da un file json e ho bisogno dell'elenco a discesa per mostrare entrambi gli elementi dell'array json uno accanto all'altro (come: "aaa, inglese" come prima scelta!)

{  
   "languages":[  
      [  
         "aaa",
         "english"
      ],
      [  
         "aab",
         "swedish"
      ],
}

3
<SelectLanguage onSelectLanguage={this.handleLanguage*Code*}/> un errore di battitura.
Yury Tarabanko,

@YuryTarabanko Grazie, ma continua a ricevere lo stesso errore
Birish,

@DavinTryon Come devo aggiungerlo? Ho provato in questo modo: handleLanguageCode: function(langValue) { this.setState({ language: langValue }).bind(this); },ma restituisce un errore:ncaught TypeError: Cannot read property 'bind' of undefined
Birish,

2
@DavinTryon createClassesegue automaticamente il vincolo dei metodi non reattivi.
Yury Tarabanko,

@OP potresti creare un violino a dimostrazione del problema?
Yury Tarabanko,

Risposte:


259

Questo dovrebbe funzionare. Mentre rispedisci il puntello, lo stai inviando come oggetto piuttosto inviandolo come valore o in alternativa utilizzalo come oggetto nel componente padre. In secondo luogo, è necessario formattare l'oggetto json in modo che contenga coppie nome-valore e usi valueFielde textFieldattributi diDropdownList

Risposta breve

Genitore:

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

Bambino:

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

dettagliata:

MODIFICARE:

Considerando che React.createClass è deprecato dalla v16.0 in poi, è meglio andare avanti e creare un componente React estendendolo React.Component. Il passaggio dei dati dal componente figlio al componente padre con questa sintassi sarà simile

Genitore

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>
        )
     }
}

Bambino

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>            
        );
    }
}

Usando la createClasssintassi che l'OP ha usato nella sua risposta 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>
        );
});

Bambino

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" 
    }, 
  ] 
}

Grazie Shubham, la tua risposta ha risolto il problema, ma non mostra l'elemento selezionato nell'elenco a discesa. Dopo ciò è vuoto: /
Birish,

@Sarah Durante la creazione di dropDownList hai assegnato il suo valore a this.state.selectedLanguage e che non è inizializzato su alcun valore. Questo potrebbe essere il problema. Quale componente DropdownList stai usando. Se lo so, forse posso lavorarci su per risolvere il problema.
Shubham Khatri,

Hai ragione. L' this.state.selectedLanguagesembra essere sempre nullo: / Sto utilizzando DropDownList dareact-widgets
Birish

@Sarah Ho apportato una piccola modifica al codice, incluso l'associazione del valore alla funzione onChange e l'impostazione di un valore di stato iniziale. Prova questo e dimmi se funziona per te
Shubham Khatri,

Restituisce un errore: Uncaught ReferenceError: value is not defined. Ho apportato questa modifica: onChange={this.handleLangChange.bind(this, this.value)}e nessun errore ritorna, ma ancora non mostra il valore selezionato :(
Birish

108

Per passare i dati dal componente figlio al componente padre

Nel componente padre:

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

Nel componente figlio:

demoMethod(){
   this.props.sendData(value);
 }

15
Non dimenticare this.getData = this.getData.bind(this);nel costruttore, in quanto potresti ottenere this.setState non è una funzione se vuoi manipolare lo stato in getData.
Miro J.,

12

Ho trovato l'approccio come ottenere dati dal componente figlio nei genitori quando ne ho bisogno.

Genitore:

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>
    )
  }
}

Bambino:

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

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

  getMapPoint(){
    return this.Point;
  }
}

Questo esempio mostra come passare la funzione dal componente figlio al padre e utilizzare questa funzione per ottenere dati dal figlio.


10

Considerando che i componenti di React Function e l'utilizzo di Hooks stanno diventando sempre più popolari in questi giorni, fornirò un semplice esempio di come passare i dati dal componente figlio a quello principale

in Componente funzione genitore avremo:

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

poi

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

e passando setChildData (che fa un lavoro simile a this.setState in Componenti di classe) a Child

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

in Child Component prima otteniamo gli oggetti di scena di ricezione

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

quindi è possibile passare comunque i dati come se si utilizzasse una funzione di gestore

const functionHandler = (data) => {

props.passChildData(data);

}

3

Il metodo React.createClass è stato deprecato nella nuova versione di React, è possibile farlo in modo molto semplice nel modo seguente per rendere un componente funzionale e un altro componente di classe per mantenere lo stato:

Genitore:

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

Bambino:

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>            
        );
    }
};


3
Solo una nota ... dovresti fare riferimento alla versione specifica di React invece che alla "nuova versione" a prova futura di questa risposta.
steve-o

3

dal componente figlio al componente padre come di seguito

componente principale

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>
        );
   }
}

componente figlio

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

Spero che questo lavoro


2

nel React v16.8+componente funzione, è possibile utilizzare useState()per creare uno stato funzione che consente di aggiornare lo stato padre, quindi passarlo a figlio come attributo props, quindi all'interno del componente figlio è possibile attivare la funzione stato padre, di seguito è riportato uno snippet funzionante :

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>


1

È anche possibile evitare che la funzione del genitore aggiorni direttamente lo stato

Nel componente padre:

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

Nel componente figlio:

demoMethod(){
   this.props.sendData(value);
}

0

L'idea è di inviare una richiamata al figlio che verrà chiamato per restituire i dati

Un esempio completo e minimale che utilizza le funzioni:

L'app creerà un figlio che calcolerà un numero casuale e lo rispedirà direttamente al genitore, che sarà console.logil risultato

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

  return <span>child</span>
}
const App = () => <Child handleRandom={(num) => console.log(num)}/>

0

Componente padre: -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}
     />

Nota : - onSelectPouringTimeDiff = {this.handleTimeValue}

Nei componenti secondari chiamare i puntelli quando richiesto

 componentDidMount():void{
      // Todo use this as per your scenrio
       this.props.onSelectPouringTimeDiff(pouringDiff);  
  }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.