¿Cómo pasar datos del componente hijo a su padre en ReactJS?
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"
],
}
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 valueField
y textField
atributo 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 createClass
la 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"
},
]
}
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);
}
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);
}
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>