Estoy escribiendo un componente simple en ES6 (con BabelJS), y las funciones this.setState
no funcionan.
Los errores típicos incluyen algo como
No se puede leer la propiedad 'setState' de undefined
o
this.setState no es una función
¿Sabes por qué? Aquí está el código:
import React from 'react'
class SomeClass extends React.Component {
constructor(props) {
super(props)
this.state = {inputContent: 'startValue'}
}
sendContent(e) {
console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
}
changeContent(e) {
this.setState({inputContent: e.target.value})
}
render() {
return (
<div>
<h4>The input form is here:</h4>
Title:
<input type="text" ref="someref" value={this.inputContent}
onChange={this.changeContent} />
<button onClick={this.sendContent}>Submit</button>
</div>
)
}
}
export default SomeClass
-- language-all: lang-js -->
La variable this.changeContent
debe estar vinculada a la instancia del componente mediante this.changeContent.bind(this)
antes de pasarla como prop de onChange
, de lo contrario la variable this
en el cuerpo de la función no se referirá a la instancia del componente sino a window
. Véase Function::bind.
Cuando se utiliza React.createClass
en lugar de clases ES6, cada método que no sea del ciclo de vida definido en un componente se vincula automáticamente a la instancia del componente. Véase Autobinding.
Tenga en cuenta que la vinculación de una función crea una nueva función. Puedes enlazarla directamente en render, lo que significa que se creará una nueva función cada vez que el componente se renderice, o enlazarla en tu constructor, que sólo se disparará una vez.
constructor() {
this.changeContent = this.changeContent.bind(this);
}
vs
render() {
return <input onChange={this.changeContent.bind(this)} />;
}
Las referencias se establecen en la instancia del componente y no en React.refs
: tienes que cambiar React.refs.someref
por this.refs.someref
. También tendrás que vincular el método sendContent
a la instancia del componente para que this
haga referencia a él.
Morhaus tiene razón, pero esto se puede resolver sin bind
.
Puede utilizar una función arrow junto con la propuesta class properties:
class SomeClass extends React.Component {
changeContent = (e) => {
this.setState({inputContent: e.target.value})
}
render() {
return <input type="text" onChange={this.changeContent} />;
}
}
Como la función flecha se declara en el ámbito del constructor, y como las funciones flecha mantienen this
desde su ámbito de declaración, todo funciona. El inconveniente aquí es que estas no serán funciones en el prototipo, todas serán recreadas con cada componente. Sin embargo, esto no es un gran inconveniente ya que bind
resulta en lo mismo.
Este problema se produce porque this.changeContent
y onClick={this.sendContent}
no están vinculados a this de la instancia del componente .
Hay otra solución (Además de utilizar bind() en el constructor() ) para utilizar las funciones de flecha de ES6 que comparten el mismo ámbito léxico del código circundante y mantener this , por lo que puede cambiar su código en render() para ser:
render() {
return (
<input type="text"
onChange={ () => this.changeContent() } />
<button onClick={ () => this.sendContent() }>Submit</button>
)
}