InputField & Button son componentes personalizados que se incluyen en un formulario para crear un formulario. Mi problema es cómo envío los datos de regreso al formulario para que al hacer clic en el botón, pueda activar ajax en el formulario con datos (nombre de usuario y contraseña):
export default auth.authApi( class SignUpViaEmail extends Component{ constructor(props){ super(props); this.state = { email : "", password : "" }; this.storeEmail = this.storeEmail.bind( this ); this.storePassword = this.storePassword.bind( this ); } storeEmail(e){ this.setState({ email : e.target.value }); } storePassword(e){ this.setState({ password : e.target.value }); } handleSignUp(){ this.props.handleSignUp(this.state); } render(){ return( <div className="pageContainer"> <form action="" method="post"> <InputField labelClass = "label" labelText = "Username" inputId = "signUp_username" inputType = "email" inputPlaceholder = "registered email" inputClass = "input" /> <Button btnClass = "btnClass" btnLabel = "Submit" onClickEvent = { handleSignUp } /> </form> </div> ); } } );¿O no se recomienda y no debería crear componentes secundarios personalizados dentro del formulario?
componente secundario => InputField
import React, { Component } from "react"; export class InputField extends Component{ constructor( props ){ super( props ); this.state = { value : "" }; this.onUserInput = this.onUserInput.bind( this ); } onUserInput( e ){ this.setState({ value : e.target.value }); this.props.storeInParentState({[ this.props.inputType ] : e.target.value }); } render(){ return <div className = ""> <label htmlFor = {this.props.inputId} className = {this.props.labelClass}> {this.props.labelText} </label> <input id = {this.props.inputId} type = {this.props.inputType} onChange = {this.onUserInput} /> <span className = {this.props.validationClass}> { this.props.validationNotice } </span> </div>; } } Error: aparece el error e.target is undefined en la función de correo electrónico de la tienda principal.
El modelo de enlace de datos unidireccional de React significa que los componentes secundarios no pueden devolver valores a los componentes principales a menos que se les permita explícitamente hacerlo . La forma React de hacer esto es pasar una devolución de llamada al componente secundario (consulte la guía de "Formularios" de Facebook ).
class Parent extends Component { constructor() { this.state = { value: '' }; } //... handleChangeValue = event => this.setState({value: event.target.value}); //... render() { return ( <Child value={this.state.value} onChangeValue={this.handleChangeValue} /> ); } } class Child extends Component { //... render() { return ( <input type="text" value={this.props.value} onChange={this.props.onChangeValue} /> ); } }Tenga en cuenta que el componente principal maneja el estado, mientras que el componente secundario solo maneja la visualización . La guía "Lifting State Up" de Facebook es un buen recurso para aprender a hacerlo.
De esta manera, todos los datos se encuentran dentro del componente principal (en estado) y los componentes secundarios solo tienen una forma de actualizar esos datos (las devoluciones de llamada se transmiten como accesorios) . Ahora su problema está resuelto: su componente principal tiene acceso a todos los datos que necesita (dado que los datos se almacenan en estado), pero sus componentes secundarios están a cargo de vincular los datos a sus propios elementos individuales, como las etiquetas <input> .
Apéndice
En respuesta a este comentario:
¿Qué sucede si representamos una lista del componente secundario? El uso de esta única fuente de verdad en la técnica de elevación del estado permitirá que el padre controle todo el estado de todas las entradas del niño, ¿verdad? Entonces, ¿cómo podemos acceder a cada entrada de valor en el componente secundario (que se representa como una lista) desde el componente principal?
Para este caso, puede asignar un componente secundario para cada elemento de la lista. Por ejemplo:
class Parent extends Component { //... handleChangeListValue = index => event => { this.setState({ list: this.state.list .map((element, i) => i === index ? event.target.value : element) }); } //... render() { return this.state.list.map((element, i) => ( <Child value={element} onChangeValue={this.handleChangeListValue(i)} /> ));Descargo de responsabilidad de PS : los ejemplos de código anteriores son solo para fines ilustrativos del concepto en cuestión (Levantamiento del estado) y reflejan el estado del código React en el momento de la respuesta. Otras preguntas sobre el código, como las actualizaciones de matrices inmutables frente a mutables, las funciones estáticas frente a las generadas dinámicamente, los componentes con estado frente a los puros y los componentes con estado basados en clases frente a los basados en ganchos, es mejor que se formulen como una pregunta separada.
Padre.js
import React, { Component } from 'react'; import Child from './child' class Parent extends Component { state = { value: '' } onChangeValueHandler = (val) => { this.setState({ value: val.target.value }) } render() { const { value } = this.state; return ( <div> <p> the value is : {value} </p> <Child value={value} onChangeValue={this.onChangeValueHandler} /> </div> ); } } export default Parent;Niño.js
import React, { Component } from 'react'; class Child extends Component { render() { const { value , onChangeValue } = this.props; return ( <div> <input type="text" value={value} onChange={onChangeValue}/> </div> ); } } export default Child;puede ver un ejemplo en vivo en: https://codesandbox.io/s/two-way-binding-qq1o1?from-embed
Puede agregar un "nombre de referencia" en su InputField para que pueda llamar a alguna función desde él, como:
<InputField ref="userInput" labelClass = "label" labelText = "Username" inputId = "signUp_username" inputType = "email" inputPlaceholder = "registered email" inputClass = "input" />Entonces puedes acceder usando refs:
this.refs.userInput.getUsernamePassword();Donde la función getUsernamePassword estaría dentro del componente InputField, y con el retorno puede establecer el estado y llamar a su props.handleSignUp