¿Cómo pasar datos del componente hijo a su padre en ReactJS?

Resuelto Birish asked hace 8 años • 20 respuestas

Estoy intentando enviar datos de un componente secundario a su principal de la siguiente manera:

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

y aquí está el componente hijo:

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

Lo que necesito es obtener el valor seleccionado por usuario en el componente principal. Recibo este error:

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

¿Alguien puede ayudarme a encontrar el problema?

PD: El componente secundario está creando un menú desplegable a partir de un archivo json y necesito que la lista desplegable muestre ambos elementos de la matriz json uno al lado del otro (como: "aaa,english" como primera opción).

{  
   "languages":[  
      [  
         "aaa",
         "english"
      ],
      [  
         "aab",
         "swedish"
      ],
}
Birish avatar Jul 15 '16 17:07 Birish
Aceptado

Esto debería funcionar. Al devolver el accesorio, lo envía como un objeto, en lugar de enviarlo como un valor o, alternativamente, usarlo como un objeto en el componente principal. En segundo lugar, debe formatear su objeto json para que contenga pares de nombre-valor y el uso valueFieldy textFieldatributo deDropdownList

Respuesta corta

Padre:

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

Niño:

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

Detallado:

EDITAR:

Teniendo en cuenta que React.createClass está en desuso desde la versión 16.0 en adelante, es mejor seguir adelante y crear un componente React extendiendo React.Component. Pasar datos del componente secundario al principal con esta sintaxis se verá así

Padre

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

Niño

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 createClassla sintaxis que el OP usó en su respuesta Padre

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

Niño

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 avatar Jul 15 '2016 13:07 Shubham Khatri

Para pasar datos del componente secundario al componente principal

En el componente principal:

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

En el componente secundario:

demoMethod(){
   this.props.sendData(value);
 }
Manisha Tan avatar Jun 09 '2017 23:06 Manisha Tan

Teniendo en cuenta que los componentes de la función React y el uso de Hooks se están volviendo más populares en estos días, daré un ejemplo simple de cómo pasar datos del componente secundario al principal.

en el componente de función principal tendremos:

import React, { useState } from "react";

entonces

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

y pasar setChildData (que hace un trabajo similar a this.setState en componentes de clase) a Child

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

en el componente secundario primero obtenemos los accesorios de recepción

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

entonces puedes pasar datos de todos modos, como usar una función de controlador

const functionHandler = (data) => {

props.passChildData(data);

}
Shayan Moghadam avatar Feb 20 '2020 07:02 Shayan Moghadam

en el React v16.8+componente de función, puede usarlo useState()para crear un estado de función que le permita actualizar el estado principal, luego pasarlo al hijo como un atributo de accesorios, luego, dentro del componente secundario, puede activar la función del estado principal, el siguiente es un fragmento de trabajo :

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>
Expandir fragmento

ROOT avatar May 15 '2020 15:05 ROOT