Pase accesorios al componente principal en React.js


295

¿No hay una manera simple de pasar un niño propsa su padre usando eventos, en React.js?

var Child = React.createClass({
  render: function() {
    <a onClick={this.props.onClick}>Click me</a>
  }
});

var Parent = React.createClass({
  onClick: function(event) {
    // event.component.props ?why is this not available?
  },
  render: function() {
    <Child onClick={this.onClick} />
  }
});

Sé que puedes usar componentes controlados para pasar el valor de una entrada, pero sería bueno pasar todo el kit n 'kaboodle. A veces, el componente secundario contiene un conjunto de información que preferiría no tener que buscar.

¿Quizás hay una manera de vincular el componente al evento?

ACTUALIZACIÓN - 9/1/2015

Después de usar React durante más de un año, y estimulado por la respuesta de Sebastien Lorber, he concluido que pasar componentes infantiles como argumentos para las funciones en los padres no es, de hecho, la forma React, ni fue una buena idea. He cambiado la respuesta.


Hay varias respuestas a problemas similares ( aquí y aquí ), pero ninguna de ellas parece particularmente elegante
Bojangles

Estoy de acuerdo: pasar eventos por la cadena es genial, pero sería increíble saber con certeza qué componente originó el evento.
KendallB

Mire mis respuestas, ya que creo que la respuesta aceptada no es lo suficientemente buena; stackoverflow.com/a/31756470/82609
Sebastien Lorber

1
kit n 'kaboodle: para incluir todo. Para obtener todas las campanas y silbatos. La combinación. urbandictionary.com/define.php?term=kit%20and%20caboodle
Filip Bartuzi

Respuestas:


268

Editar : vea los ejemplos finales para los ejemplos actualizados de ES6.

Esta respuesta simplemente maneja el caso de la relación directa padre-hijo. Cuando padre e hijo tengan potencialmente muchos intermediarios, marque esta respuesta .

Otras soluciones están perdiendo el punto

Si bien aún funcionan bien, a otras respuestas les falta algo muy importante.

¿No hay una manera simple de pasar los accesorios de un niño a su padre usando eventos, en React.js?

¡El padre ya tiene ese accesorio de niño! : si el niño tiene un accesorio, ¡es porque su padre le proporcionó ese accesorio al niño! ¿Por qué quieres que el niño pase el accesorio al padre, mientras que el padre obviamente ya tiene ese accesorio?

Mejor implementación

Niño : realmente no tiene que ser más complicado que eso.

var Child = React.createClass({
  render: function () {
    return <button onClick={this.props.onClick}>{this.props.text}</button>;
  },
});

Padre con hijo único : usando el valor que le pasa al hijo

var Parent = React.createClass({
  getInitialState: function() {
     return {childText: "Click me! (parent prop)"};
  },
  render: function () {
    return (
      <Child onClick={this.handleChildClick} text={this.state.childText}/>
    );
  },
  handleChildClick: function(event) {
     // You can access the prop you pass to the children 
     // because you already have it! 
     // Here you have it in state but it could also be
     //  in props, coming from another parent.
     alert("The Child button text is: " + this.state.childText);
     // You can also access the target of the click here 
     // if you want to do some magic stuff
     alert("The Child HTML is: " + event.target.outerHTML);
  }
});

JsFiddle

Padre con lista de hijos : todavía tiene todo lo que necesita en el padre y no necesita complicarlo más.

var Parent = React.createClass({
  getInitialState: function() {
     return {childrenData: [
         {childText: "Click me 1!", childNumber: 1},
         {childText: "Click me 2!", childNumber: 2}
     ]};
  },
  render: function () {
    var children = this.state.childrenData.map(function(childData,childIndex) {
        return <Child onClick={this.handleChildClick.bind(null,childData)} text={childData.childText}/>;
    }.bind(this));
    return <div>{children}</div>;
  },

  handleChildClick: function(childData,event) {
     alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
     alert("The Child HTML is: " + event.target.outerHTML);
  }
});

JsFiddle

También es posible usar this.handleChildClick.bind(null,childIndex)y luego usarthis.state.childrenData[childIndex]

Tenga en cuenta que estamos vinculados con un nullcontexto porque, de lo contrario, React emite una advertencia relacionada con su sistema de enlace automático. Usar nulo significa que no desea cambiar el contexto de la función. Ver también .

Sobre encapsulación y acoplamiento en otras respuestas

Esta es para mí una mala idea en términos de acoplamiento y encapsulación:

var Parent = React.createClass({
  handleClick: function(childComponent) {
     // using childComponent.props
     // using childComponent.refs.button
     // or anything else using childComponent
  },
  render: function() {
    <Child onClick={this.handleClick} />
  }
});

Uso de accesorios : como expliqué anteriormente, ya tiene los accesorios en el padre, por lo que es inútil pasar todo el componente hijo para acceder a los accesorios.

Uso de referencias : ya tiene el objetivo de clic en el evento, y en la mayoría de los casos esto es suficiente. Además, podría haber usado una referencia directamente sobre el niño:

<Child ref="theChild" .../>

Y acceda al nodo DOM en el padre con

React.findDOMNode(this.refs.theChild)

Para casos más avanzados en los que desea acceder a múltiples referencias del niño en el padre, el niño podría pasar todos los nodos dom directamente en la devolución de llamada.

El componente tiene una interfaz (accesorios) y el padre no debe asumir nada sobre el funcionamiento interno del niño, incluida su estructura DOM interna o para qué nodos DOM declara referencias. Un padre que usa una referencia de un niño significa que acopla firmemente los 2 componentes.

Para ilustrar el problema, tomaré esta cita sobre Shadow DOM , que se usa dentro de los navegadores para representar elementos como controles deslizantes, barras de desplazamiento, reproductores de video ...:

Crearon un límite entre lo que usted, el desarrollador web puede alcanzar y lo que se considera detalles de implementación, por lo tanto, inaccesible para usted. Sin embargo, el navegador puede atravesar este límite a voluntad. Con este límite en su lugar, pudieron construir todos los elementos HTML utilizando las mismas tecnologías web antiguas, fuera de los divs y los tramos, como lo haría usted.

El problema es que si deja que los detalles de implementación secundarios se filtren en el elemento primario, le resultará muy difícil refactorizar el elemento secundario sin afectarlo. Esto significa que, como autor de la biblioteca (o como editor del navegador con Shadow DOM), esto es muy peligroso porque permite que el cliente acceda demasiado, lo que dificulta la actualización del código sin romper la retrocompatibilidad.

Si Chrome hubiera implementado su barra de desplazamiento permitiendo que el cliente acceda a los nodos dom internos de esa barra de desplazamiento, esto significa que el cliente puede tener la posibilidad de simplemente romper esa barra de desplazamiento, y que las aplicaciones se romperían más fácilmente cuando Chrome realiza su actualización automática después de refactorizar el barra de desplazamiento ... En cambio, solo dan acceso a algunas cosas seguras como personalizar algunas partes de la barra de desplazamiento con CSS.

Sobre usar cualquier otra cosa

Pasar todo el componente en la devolución de llamada es peligroso y puede dar lugar a los desarrolladores novatos que hacer cosas muy extrañas como llamar childComponent.setState(...)o childComponent.forceUpdate(), o asignándole nuevas variables, dentro de la matriz, por lo que toda la aplicación mucho más difícil de razonar acerca.


Editar: ejemplos de ES6

Como muchas personas ahora usan ES6, estos son los mismos ejemplos para la sintaxis de ES6

El niño puede ser muy simple:

const Child = ({
  onClick, 
  text
}) => (
  <button onClick={onClick}>
    {text}
  </button>
)

El padre puede ser una clase (y eventualmente puede administrar el estado en sí, pero lo paso como accesorio aquí:

class Parent1 extends React.Component {
  handleChildClick(childData,event) {
     alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
     alert("The Child HTML is: " + event.target.outerHTML);
  }
  render() {
    return (
      <div>
        {this.props.childrenData.map(child => (
          <Child
            key={child.childNumber}
            text={child.childText} 
            onClick={e => this.handleChildClick(child,e)}
          />
        ))}
      </div>
    );
  }
}

Pero también se puede simplificar si no necesita administrar el estado:

const Parent2 = ({childrenData}) => (
  <div>
     {childrenData.map(child => (
       <Child
         key={child.childNumber}
         text={child.childText} 
         onClick={e => {
            alert("The Child button data is: " + child.childText + " - " + child.childNumber);
                    alert("The Child HTML is: " + e.target.outerHTML);
         }}
       />
     ))}
  </div>
)

JsFiddle


ADVERTENCIA PERF (aplica a ES5 / ES6): si está utilizando PureComponento shouldComponentUpdate, las implementaciones anteriores no se optimizarán de manera predeterminada porque se usan onClick={e => doSomething()}o se vinculan directamente durante la fase de representación, ya que creará una nueva función cada vez que se muestre el elemento primario. Si se trata de un cuello de botella de rendimiento en su aplicación, puede pasar los datos a los elementos secundarios y reinyectarlos dentro de la devolución de llamada "estable" (establecida en la clase principal y vinculada al thisconstructor de la clase) para que la PureComponentoptimización pueda iniciarse, o usted puede implementar el suyo propio shouldComponentUpdatee ignorar la devolución de llamada en la verificación de comparación de accesorios.

También puede usar la biblioteca Recompose , que proporciona componentes de orden superior para lograr optimizaciones ajustadas:

// A component that is expensive to render
const ExpensiveComponent = ({ propA, propB }) => {...}

// Optimized version of same component, using shallow comparison of props
// Same effect as React's PureRenderMixin
const OptimizedComponent = pure(ExpensiveComponent)

// Even more optimized: only updates if specific prop keys have changed
const HyperOptimizedComponent = onlyUpdateForKeys(['propA', 'propB'])(ExpensiveComponent)

En este caso, podría optimizar el componente Hijo utilizando:

const OptimizedChild = onlyUpdateForKeys(['text'])(Child)

1
Sí, después de haber pasado el último año usando React, estoy de acuerdo, no hay una buena razón para pasar componentes instanciados a través de funciones. Voy a desaprobar mi propia respuesta. También estoy dispuesto a cambiar la respuesta, con quizás algunas modificaciones: su "Mejor implementación" no aborda la razón real por la que surgió esta pregunta, que es: "¿Cómo sé cuál de mis hijos fue elegido entre un grupo?" Flux es la respuesta para cualquier aplicación de tamaño decente, sin embargo, en aplicaciones pequeñas, es bueno pasar valores (no componentes) respaldar la cadena de llamadas a través de una función props. ¿De acuerdo?
KendallB

@KendallB me alegra que esté de acuerdo con mi respuesta :) How do I know which of my children was chosen among a group?esto no es realmente parte de la pregunta original, pero incluí la solución en mi respuesta. A diferencia de su edición, creo que no es necesario modificar el niño en absoluto, incluso cuando se trata de una lista, ya que puede usarlo binddirectamente en el padre.
Sebastien Lorber

Hice una edición a su respuesta, la parte sobre referencias. omerwazir.com/posts/react-getdomnode-replaced-with-findDOMNode
ffxsam

Hola @SebastienLorber, vengo del futuro. Con respecto a esta línea onClick={this.handleChildClick.bind(null,childData)}que mencionó sobre la vinculación automática, ¿sigue siendo aplicable ahora que React no se ha incluido en el modelo de clase ? He leído muchas cosas, pero esta parte todavía me confunde. Por class modelcierto, estoy usando ES6 , así que cambié nulla thisy mi código todavía parece funcionar. ¿Cómo traducirías esa parte de tu código al estilo ES6?
JohnnyQ

También estoy luchando para que esto funcione en la última React, ¿qué necesita cambiar?
Hussein Duvigneau

143

Actualización (1/9/15): El OP ha convertido esta pregunta en un objetivo móvil. Ha sido actualizado nuevamente. Entonces, me siento responsable de actualizar mi respuesta.

Primero, una respuesta a su ejemplo proporcionado:

Si, esto es posible.

Puede resolver esto actualizando Child's onClickpara que sea this.props.onClick.bind(null, this):

var Child = React.createClass({
  render: function () {
    return <a onClick={this.props.onClick.bind(null, this)}>Click me</a>;
  }
});

El controlador de eventos en su padre puede acceder al componente y al evento de la siguiente manera:

  onClick: function (component, event) {
    // console.log(component, event);
  },

Instantánea de JSBin


Pero la pregunta en sí es engañosa

El padre ya sabe del niño props.

Esto no está claro en el ejemplo proporcionado porque en realidad no se proporcionan accesorios. Este código de muestra podría respaldar mejor la pregunta que se hace:

var Child = React.createClass({
  render: function () {
    return <a onClick={this.props.onClick}> {this.props.text} </a>;
  }
});

var Parent = React.createClass({
  getInitialState: function () {
    return { text: "Click here" };
  },
  onClick: function (event) {
    // event.component.props ?why is this not available? 
  },
  render: function() {
    return <Child onClick={this.onClick} text={this.state.text} />;
  }
});

Se vuelve mucho más claro en este ejemplo que ya sabes cuáles son los accesorios del Niño.

Instantánea de JSBin


Si realmente se trata de usar los accesorios de un niño ...

Si realmente se trata de usar los accesorios de un niño, puede evitar cualquier conexión con el niño por completo.

JSX tiene una API de atributos extendidos que uso a menudo en componentes como Child. Toma todo propsy los aplica a un componente. El niño se vería así:

var Child = React.createClass({
  render: function () {
    return <a {...this.props}> {this.props.text} </a>;
  }
});

Permitiéndole usar los valores directamente en el padre:

var Parent = React.createClass({
  getInitialState: function () {
    return { text: "Click here" };
  },
  onClick: function (text) {
    alert(text);
  },
  render: function() {
    return <Child onClick={this.onClick.bind(null, this.state.text)} text={this.state.text} />;
  }
});

Instantánea de JSBin


Y no se requiere configuración adicional a medida que conecta componentes secundarios adicionales

var Parent = React.createClass({
  getInitialState: function () {
    return {
      text: "Click here",
      text2: "No, Click here",
    };
  },
  onClick: function (text) {
    alert(text);
  },
  render: function() {
    return <div>
      <Child onClick={this.onClick.bind(null, this.state.text)} text={this.state.text} />
      <Child onClick={this.onClick.bind(null, this.state.text2)} text={this.state.text2} />
    </div>;
  }
});

Instantánea de JSBin

Pero sospecho que ese no es su caso de uso real. Así que vamos a cavar más ...


Un ejemplo práctico robusto

Es difícil hablar de la naturaleza genérica del ejemplo proporcionado. He creado un componente que demuestra un uso práctico para la pregunta anterior, implementado de una manera muy reactiva :

Ejemplo de trabajo de DTServiceCalculator Repo
DTServiceCalculator

Este componente es una calculadora de servicio simple. Le proporciona una lista de servicios (con nombres y precios) y calculará un total de los precios seleccionados.

Los niños son felizmente ignorantes

ServiceItemes el componente hijo en este ejemplo. No tiene muchas opiniones sobre el mundo exterior. Se requiere un par de apoyos , uno de los cuales es una función que se llamará cuando se hace clic.

<div onClick={this.props.handleClick.bind(this.props.index)} />

No hace nada más que llamar a la handleClickdevolución de llamada proporcionada con la index[ fuente ] proporcionada .

Los padres son niños

DTServicesCalculatores el componente principal es este ejemplo. También es un niño. Miremos.

DTServiceCalculatorcrea una lista de componentes secundarios ServiceItemy les proporciona accesorios [ fuente ]. Es el componente principal de ServiceItempero es el componente secundario del componente que le pasa la lista. No posee los datos. Por lo tanto, delega nuevamente el manejo del componente a su fuente de componente principal

<ServiceItem chosen={chosen} index={i} key={id} price={price} name={name} onSelect={this.props.handleServiceItem} />

handleServiceItemcaptura el índice, se pasa del elemento secundario y se lo proporciona a su elemento primario [ fuente ]

handleServiceClick (index) {
  this.props.onSelect(index);
}

Los dueños lo saben todo

El concepto de "Propiedad" es importante en React. Recomiendo leer más sobre esto aquí .

En el ejemplo que he mostrado, sigo delegando el manejo de un evento en el árbol de componentes hasta que lleguemos al componente que posee el estado.

Cuando finalmente llegamos allí, manejamos la selección / deselección de estado de la siguiente manera [ fuente ]

handleSelect (index) {
  let services = […this.state.services];
  services[index].chosen = (services[index].chosen) ? false : true;
  this.setState({ services: services });
}


Conclusión

Intente mantener sus componentes más externos lo más opacos posible. Esfuércese por asegurarse de que tengan muy pocas preferencias sobre cómo un componente principal podría elegir implementarlas.

Tenga en cuenta quién posee los datos que está manipulando. En la mayoría de los casos, deberá delegar el manejo de eventos en el árbol al componente que posee ese estado.

Aparte: el patrón Flux es una buena forma de reducir este tipo de conexión necesaria en las aplicaciones.


Gracias por la respuesta concisa, realmente me ayudó a entender ¡Reaccionar un poco mejor! Tengo una pregunta en la misma línea. Estoy usando Flux para pub / sub. En lugar de pasar el controlador de eventos Child al Parent como su ejemplo, es posible implementar esto como una 'acción' y escucharlo. ¿Consideraría que esta es una buena alternativa y uso de Flux?
Pathsofdesign

1
Gracias @Pathsofdesign! Dependería Flux tiene este concepto de vistas de controlador. En este ejemplo, Parentpodría tratarse de una Vista de controlador, mientras Childque solo es una Vista tonta (componente). Solo Controller-Views debe tener conocimiento de la aplicación. En este caso, aún pasarías la Acción de Parenta Childcomo un accesorio. En lo que respecta a la acción en sí, Flux tiene un patrón fuertemente prescrito para interactuar entre las acciones para actualizar las vistas. facebook.github.io/flux/docs/…
fantástico

1
onClick={this.onClick.bind(null, this.state.text)}no es necesario vincular el estado ya que el padre tiene eso. así que solo onClick={this.onClick}funcionará. donde onClick = ()=>{const text = this.state.text;..}en los padres
Shishir Arora

25

Parece que hay una respuesta simple. Considera esto:

var Child = React.createClass({
  render: function() {
    <a onClick={this.props.onClick.bind(null, this)}>Click me</a>
  }
});

var Parent = React.createClass({
  onClick: function(component, event) {
    component.props // #=> {Object...}
  },
  render: function() {
    <Child onClick={this.onClick} />
  }
});

La clave está llamando bind(null, this)al this.props.onClickevento, pasado del padre. Ahora, la función onClick acepta argumentos component, AND event. Creo que es el mejor de todos los mundos.

ACTUALIZACIÓN: 1/9/2015

Esta fue una mala idea: dejar que los detalles de implementación secundarios se filtren a los padres nunca fue un buen camino. Ver la respuesta de Sebastien Lorber.


¿No son los argumentos de la manera incorrecta (lugares intercambiados)?
The Surrican

1
@TheSurrican No, está perfectamente bien. El primer argumento está vinculado thisdentro de la función (que de todos modos no es necesario), y el segundo se antepone como primer argumento cuando se llama a onClick.
manmal

13

La pregunta es cómo pasar el argumento del componente hijo al padre. Este ejemplo es fácil de usar y probado:

//Child component
class Child extends React.Component {
    render() {
        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div><button onClick={() => handleToUpdate('someVar')}>Push me</button></div>
        )
    }
}

//Parent component
class Parent extends React.Component {
    constructor(props) {
        super(props);
        var handleToUpdate  = this.handleToUpdate.bind(this);
    }

    handleToUpdate(someArg){
        alert('We pass argument from Child to Parent: \n' + someArg);
    }

    render() {
        var handleToUpdate  =   this.handleToUpdate;
        return (<div>
          <Child handleToUpdate = {handleToUpdate.bind(this)} />
        </div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <Parent />,
        document.querySelector("#demo")
    );
}

Mira JSFIDDLE


En mi caso, olvido pasar la función de devolución de llamada a click ()
Long Nguyen

6

Básicamente, utiliza accesorios para enviar información hacia y desde el niño y el padre.

Agregando a todas las maravillosas respuestas, permítanme dar un ejemplo simple que explica pasar valores del componente hijo al padre en React

App.js

class App extends React.Component {
      constructor(){
            super();
            this.handleFilterUpdate = this.handleFilterUpdate.bind(this);
            this.state={name:'igi'}
      }
      handleFilterUpdate(filterValue) {
            this.setState({
                  name: filterValue
            });
      }
   render() {
      return (
        <div>
            <Header change={this.handleFilterUpdate} name={this.state.name} />
            <p>{this.state.name}</p>
        </div>
      );
   }
}

Header.js

class Header extends React.Component {
      constructor(){
            super();
            this.state={
                  names: 'jessy'
            }
      }
      Change(event) {

      // this.props.change(this.state.names);
      this.props.change('jessy');
  }

   render() {
      return (
       <button onClick={this.Change.bind(this)}>click</button>

      );
   }
}

Main.js

import React from 'react';
import ReactDOM from 'react-dom';

import App from './App.jsx';

ReactDOM.render(<App />, document.getElementById('app'));

Eso es todo, ahora puede pasar valores de su cliente al servidor.

Eche un vistazo a la función Cambiar en Header.js

Change(event) {
      // this.props.change(this.state.names);
      this.props.change('jessy');
  }

Así es como inserta valores en los accesorios del cliente al servidor


¿Se puede saber así es como se presiona valores en los apoyos desde el cliente al servidor, ¿qué es lo que quiere decir con esta declaración
G1P

2

Aquí hay una implementación simple de ES6 de 3 pasos usando el enlace de función en el constructor padre. Esta es la primera forma en que el tutorial de reacción oficial recomienda (también hay una sintaxis de campos de clase pública que no se cubre aquí). Puede encontrar toda esta información aquí https://reactjs.org/docs/handling-events.html

Vinculando las funciones de los padres para que los niños puedan llamarlos (¡Y pasar datos al padre!: D)

  1. Asegúrese de que en el constructor principal, enlace la función que creó en el padre
  2. Pase la función enlazada al niño como un accesorio (Sin lambda porque estamos pasando una referencia a la función)
  3. Llamar a la función enlazada desde un evento secundario (¡Lambda! Llamamos a la función cuando se dispara el evento. Si no hacemos esto, la función se ejecutará automáticamente al cargarse y no se activará en el evento).

Función principal

handleFilterApply(filterVals){} 

Constructor principal

this.handleFilterApply = this.handleFilterApply.bind(this);

Prop transmitido al niño

onApplyClick = {this.handleFilterApply}

Llamada de evento infantil

onClick = {() => {props.onApplyClick(filterVals)}

0

Este es un ejemplo sin usar el evento onClick. Simplemente paso una función de devolución de llamada al niño por accesorios. Con esa devolución de llamada, la llamada secundaria también devuelve datos. Me inspiraron los ejemplos en los documentos .

Pequeño ejemplo (esto está en un archivo tsx, por lo que los accesorios y los estados deben declararse por completo, eliminé algo de lógica de los componentes, por lo que es menos código).

* Actualización: es importante vincular esto a la devolución de llamada, de lo contrario, la devolución de llamada tiene el alcance del elemento secundario y no del principal. El único problema: es el padre "viejo" ...

SymptomChoser es el padre:

interface SymptomChooserState {
  // true when a symptom was pressed can now add more detail
  isInDetailMode: boolean
  // since when user has this symptoms
  sinceDate: Date,
}

class SymptomChooser extends Component<{}, SymptomChooserState> {

  state = {
    isInDetailMode: false,
    sinceDate: new Date()
  }

  helloParent(symptom: Symptom) {
    console.log("This is parent of: ", symptom.props.name);
    // TODO enable detail mode
  }

  render() {
    return (
      <View>
        <Symptom name='Fieber' callback={this.helloParent.bind(this)} />
      </View>
    );
  }
}

El síntoma es el niño (en los accesorios del niño declare la función de devolución de llamada, en la función seleccionada Síntoma se llama la devolución de llamada):

interface SymptomProps {
  // name of the symptom
  name: string,
  // callback to notify SymptomChooser about selected Symptom.
  callback: (symptom: Symptom) => void
}

class Symptom extends Component<SymptomProps, SymptomState>{

  state = {
    isSelected: false,
    severity: 0
  }

  selectedSymptom() {
    this.setState({ isSelected: true });
    this.props.callback(this);
  }

  render() {
    return (
      // symptom is not selected
      <Button
        style={[AppStyle.button]}
        onPress={this.selectedSymptom.bind(this)}>
        <Text style={[AppStyle.textButton]}>{this.props.name}</Text>
      </Button>
    );
  }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.