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

213

Estoy tratando de enviar datos desde un componente hijo a su padre 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, inglés" como la primera opción!)

{  
   "languages":[  
      [  
         "aaa",
         "english"
      ],
      [  
         "aab",
         "swedish"
      ],
}
Birish
fuente
3
<SelectLanguage onSelectLanguage={this.handleLanguage*Code*}/> un error.
Yury Tarabanko
@YuryTarabanko Gracias, pero sigue recibiendo el mismo error
Birish
@Davin Tryon ¿Cómo debo agregarlo? Lo intenté así: handleLanguageCode: function(langValue) { this.setState({ language: langValue }).bind(this); },pero devuelve un error:ncaught TypeError: Cannot read property 'bind' of undefined
Birish
2
@Davin createClassTryon enlaza automáticamente los métodos sin reacción.
Yury Tarabanko
@OP, ¿podrías crear un violín que demuestre el problema?
Yury Tarabanko

Respuestas:

259

Esto debería funcionar. Al devolver el accesorio, lo está enviando como un objeto, en lugar de enviarlo como un valor o, alternativamente, utilizarlo como un objeto en el componente principal. En segundo lugar, debe formatear su objeto json para que contenga pares de valores de nombre 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 extendiéndolo React.Component. Pasar datos del componente hijo al padre 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 la createClasssintaxis que el OP utilizó en su respuesta 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>
        );
});

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
fuente
Gracias Shubham, su respuesta solucionó el problema, pero no muestra el elemento seleccionado en la lista desplegable. Está vacío después de eso: /
Birish
@Sarah Al crear dropDownList, asignó su valor para que sea this.state.selectedLanguage y eso no se inicializa a ningún valor. Ese puede ser el problema. ¿Qué componente de DropdownList estás usando? Si sé, tal vez pueda trabajar en eso para resolver el problema.
Shubham Khatri
Tienes razón. El this.state.selectedLanguageparece estar siempre nulo: / estoy usando DROPDOWNLIST dereact-widgets
Birish
@Sarah He realizado un pequeño cambio en el código, incluido el enlace del valor a la función onChange y el establecimiento de un valor de estado inicial. Prueba esto y dime si te funciona
Shubham Khatri
Devuelve un error: Uncaught ReferenceError: value is not defined. Hice este cambio: onChange={this.handleLangChange.bind(this, this.value)}y no devuelve ningún error, pero aún así no muestra el valor seleccionado :(
Birish
108

Para pasar datos del componente secundario al componente primario

En el componente principal:

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

En componente infantil:

demoMethod(){
   this.props.sendData(value);
 }
Manisha Tan
fuente
15
No olvide this.getData = this.getData.bind(this);en el constructor, ya que puede obtener esto. SetState no es una función si desea manipular el estado en getData.
Miro J.
12

Encontré el enfoque de cómo obtener datos del componente hijo en los padres cuando lo necesito.

Padre:

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

Niño:

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

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

  getMapPoint(){
    return this.Point;
  }
}

Este ejemplo muestra cómo pasar la función del componente hijo al padre y usar esta función para obtener datos del hijo.

MrDuDuDu
fuente
10

Considerando los componentes de la función React y usando ganchos 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, useEffect } from "react";

luego

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

y pasar setChildData (que hace un trabajo similar a this.setState en Class Components) a Child

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

en Child Component primero obtenemos los accesorios de recepción

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

entonces puede pasar datos de cualquier manera como usar una función de controlador

const functionHandler = (data) => {

props.passChildData(data);

}
Shayan Moghadam
fuente
3

El método React.createClass ha quedado en desuso en la nueva versión de React, puede hacerlo de la siguiente manera para hacer que un componente funcional y otro componente de clase mantengan el estado:

Padre:

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

Niño:

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
fuente
3
Solo una nota ... debe hacer referencia a la versión específica de React en lugar de "la nueva versión" para probar esta respuesta en el futuro.
Steve-o
3

del componente hijo al componente padre como se muestra a continuación

componente principal

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 hijo

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

Espero este trabajo

Manoj Rana
fuente
2

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 primario, luego pasarlo al secundario como un atributo de utilería, luego dentro del componente secundario puede activar la función de estado primario, 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>

RAÍZ
fuente
1

Incluso puede evitar que la función en el padre actualice el estado directamente

En el componente principal:

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

En el componente hijo:

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

La idea es enviar una devolución de llamada al niño que se llamará para devolver los datos

Un ejemplo completo y mínimo con funciones:

La aplicación creará un hijo que calculará un número aleatorio y lo enviará directamente al padre, lo que dará console.logcomo resultado

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

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

Componente principal: -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}

En el componente secundario, llame a accesorios cuando sea necesario

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