reactjs - Manejadores de eventos de React con Typescript y JSX
Estoy teniendo problemas para actualizar el estado en un componente de React que estoy escribiendo en TypeScript (React con Addons 0.13.3, TypeScript 1.6.0-dev.20150804, archivo de definición de http://definitelytyped.org/).
/// <reference path="react/react-addons.d.ts" />
import React = require("react/addons");
interface AppState {
}
interface TestState {
liked: boolean,
name: string
}
class Tester extends React.Component<any, TestState> {
constructor(props) {
super(props);
this.state = { liked: false, name: "Anders" };
}
handleClick(evt, domNode): void {
this.setState({ liked: !this.state.liked, name: this.state.name });
}
handleChange(evt, a, b, c): void {
this.setState({ liked: this.state.liked, name: evt.target.value });
}
render() {
var text = this.state.liked ? "liked " : "haven't liked "
return (<div>You {text} {this.state.name}
<button onClick={this.handleClick}>Like</button>
<input value={this.state.name} onChange={this.handleChange} />
</div>);
}
}
class App extends React.Component<{}, AppState> {
constructor(props) {
super(props);
}
render() {
return (<div>
<Tester />
</div>);
}
}
function Factory(props: {}) {
return React.createElement(App, props);
}
export = Factory;
El código de llamada es
/// <reference path="react/react-addons.d.ts" />
import React = require("react/addons");
import App = require("app");
React.render(App({}), document.getElementById("jsapp"));
El componente se renderiza como esperaría, pero los métodos handleClick y handleChange no actualizan el estado correctamente. Si pongo puntos de interrupción en esos dos métodos y en render, entonces veo los siguientes valores para this:
render:thises un objeto Tester (lo que esperaría).handleChange:thises unReactClass.createClass.Constructor.handleClick:thises una referencia al objetoWindow.
Los dos últimos significan que el objeto de estado no está disponible.
Cualquier sugerencia será recibida con gratitud.
Respuesta #1
Tienes que enlazar los métodos con this porque no usas React.createClass que lo hace automáticamente. Ejemplo con una sintaxis de clase:
class Counter extends React.Component {
constructor() {
super();
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleChange() {
...
}
handleClick() {
...
}
}
Respuesta #2
Debes cambiar tu método de renderizado:
render() {
// ...
<button onClick={this.handleClick.bind(this)}>Like</button>
<input value={this.state.name} onChange={this.handleChange.bind(this)} />
// ...
}
Dado que estás llamando a un evento, la palabra clave this se cambiará al contexto predeterminado del evento. Al usar .bind(this) aseguras que el contexto que se llame será la instancia de tu clase.
Respuesta #3
Otro método es usar funciones de flecha para los controladores de eventos, las cuales obtienen una vinculación automática de "this".
handleClick = (evt, domNode):void => {
this.setState({ liked: !this.state.liked, name: this.state.name });
};
<button onClick={() => this.handleClick()}>Like</button>
