I'm having problems updating state in a React component I'm writing in TypeScript (React with Addons 0.13.3, Typescript 1.6.0-dev.20150804, definition file from 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;
The calling code is
/// <reference path="react/react-addons.d.ts" />
import React = require("react/addons");
import App = require("app");
React.render(App({}), document.getElementById("jsapp"));
The component renders as I would expect but handleClick
and handleChange
methods don't update the state correctly. If I put breakpoints in those two methods and render
then I see the following values for this
:
render
: this
is a Tester object (what I would expect).handleChange
: this
is a ReactClass.createClass.Constructor
.handleClick
: this
is a reference to the Window
object.The latter two mean that the state object isn't available.
Any suggestions gratefully received.
TypeScript supports embedding, type checking, and compiling JSX directly to JavaScript.
To type the onClick event of an element in React, set its type to React. MouseEvent<HTMLElement> . The MouseEvent interface is used to type onClick events in React.
You have to bind methods with this
because you don't use React.createClass
that does it automatically.
Example with a class syntax:
class Counter extends React.Component {
constructor() {
super();
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleChange() {
...
}
handleClick() {
...
}
}
You must change your render method:
render() {
// ...
<button onClick={this.handleClick.bind(this)}>Like</button>
<input value={this.state.name} onChange={this.handleChange.bind(this)} />
// ...
}
Since you're calling an event, the this
keyword will be changed to the event's default context.
By using .bind(this)
you ensure that the context being called will be the instance of your class.
Another method is to use fat arrow functions for event handlers which get automatic "this" binding.
handleClick = (evt, domNode):void => {
this.setState({ liked: !this.state.liked, name: this.state.name });
};
<button onClick={() => this.handleClick()}>Like</button>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With