Recibo el error: Uncaught TypeError: Cannot read properties of undefined (reading 'state') aunque state esté definido en el constructor de mi componente React. Recibo el error en la línea donde establecí el valor de <input> en {this.state.deckName}
export class DeckForm extends React.Component { constructor(props) { super(props); this.state = { deckName: '', deckList: '' }; // Bind our event handler methods to this class this.handleDeckNameChange = this.handleDeckNameChange.bind(this); this.handleDeckListChange = this.handleDeckListChange.bind(this); this.handleSubmission = this.handleSubmission.bind(this); } // Event handler method to update the state of the deckName each time a user types into the input form element handleDeckNameChange(event) { let typed = event.target.value; this.setState({ deckName: typed }); } // Event handler method to update the state of the deckList each time a user types into the textarea from element] handleDeckListChange(event) { let typed = event.target.value; this.setState({ deckList: typed }); } // Event handler method to handle validation of deckName and deckList handleSubmission(event) { console.log(`${this.state.deckName}`); console.log(`${this.state.deckList}`) } render() { return ( <form className='was-validated'> <this.DeckName /> <this.DeckList /> <button type='submit' className='btn-lg btn-warning mt-3'>Create</button> </form> ); } DeckName() { return ( <div className='form-group mb-3'> <input value={this.state.deckName} /* ERROR HERE */ onChange={this.handleDeckNameChange} type='text' placeholder='Deck name' className='form-control' required /> </div> ); } DeckList() { let format = 'EXACT CARD NAME 1\nPot of Greed 3\nChange of Heart 3\nGraceful Charity 3' return ( <div className='form-group'> <textarea value={this.state.deckList} onChange={this.handleDeckListChange} className='form-control' rows='15' required > {format} </textarea> </div> ); } }Use el código a continuación, está funcionando para mí
https://codesandbox.io/s/weathered-water-jm1ydv?file=/src/App.js
DeckName() { return ( <div className="form-group mb-3"> <input value={this?.state.deckName} /* ERROR HERE */ onChange={this?.handleDeckNameChange} type="text" placeholder="Deck name" className="form-control" required /> </div> ); } DeckList() { let format = "EXACT CARD NAME 1\nPot of Greed 3\nChange of Heart 3\nGraceful Charity 3"; return ( <div className="form-group"> <textarea value={this?.state.deckList} onChange={this?.handleDeckListChange} className="form-control" rows="15" required > {format} </textarea> </div> ); }Puede usar la función es6 para devolver componentes que existen fuera del padre en lugar de usar el método, cambie solo esta parte del código:
1.en lugar de DeckName(){...} use DeckName =()=>{....} 2.en lugar de DeckList(){...} use DeckList =()=>{....}
Código modificado completo:
import React, { Component } from "react"; export class DeckForm extends Component { constructor(props) { super(props); this.state = { deckName: "", deckList: "" }; // Bind our event handler methods to this class this.handleDeckNameChange = this.handleDeckNameChange.bind(this); this.handleDeckListChange = this.handleDeckListChange.bind(this); this.handleSubmission = this.handleSubmission.bind(this); } // Event handler method to update the state of the deckName each time a user types into the input form element handleDeckNameChange(event) { let typed = event.target.value; this.setState({ deckName: typed }); } // Event handler method to update the state of the deckList each time a user types into the textarea from element] handleDeckListChange(event) { let typed = event.target.value; console.log(typed); this.setState({ deckList: typed }); } // Event handler method to handle validation of deckName and deckList handleSubmission(event) { console.log(`${this.state.deckName}`); console.log(`${this.state.deckList}`); } render() { return ( <form className="was-validated"> <this.DeckName /> <this.DeckList /> <button type="submit" className="btn-lg btn-warning mt-3"> Create </button> </form> ); } DeckName = () => { return ( <div className="form-group mb-3"> <input value={this.state.deckName} onChange={this.handleDeckNameChange} type="text" placeholder="Deck name" className="form-control" required /> </div> ); }; DeckList = () => { let format = "EXACT CARD NAME 1\nPot of Greed 3\nChange of Heart 3\nGraceful Charity 3"; return ( <div className="form-group"> <textarea value={this.state.deckList} onChange={this.handleDeckListChange} className="form-control" rows="15" required > {format} </textarea> </div> ); }; }Demostración en vivo: https://codesandbox.io/s/brave-hill-l0eknx?file=/src/DeckForm.js:0-2091
Otra forma de resolver el problema es definir el método DeckName() usando la función de flecha. Aquí hay un fragmento de código que probé con reaccionar 17.0.2 que funcionó perfectamente bien para mí.
Siempre se recomienda usar la función de flecha para definir métodos en componentes basados en clases, ya que la función de flecha hereda "esto" del bloque desde el que se llama, por lo que tampoco tiene que hacer .bind(esto) cada vez que llama a los métodos.
JSX
import React, { Component } from 'react' class Test extends Component { constructor(props) { super(props); this.state = { deckName: '', deckList: '' }; } DeckName = () => { return ( <div className='form-group mb-3'> <input value={this.state.deckName} /* ERROR HERE */ onChange={this.handleDeckNameChange} type='text' placeholder='Deck name' className='form-control' required /> </div> ); } render() { return ( <form className='was-validated'> <this.DeckName /> <button type='submit' className='btn-lg btn-warning mt-3'>Create</button> </form> ); } } export default Test