Reactjs - هندلرهای رویداد React با Typescript و JSX


من در بهروزرسانی state در یک کامپوننت React که با TypeScript مینویسم مشکل دارم (React با Addons نسخه 0.13.3، TypeScript نسخه 1.6.0-dev.20150804، فایل تعریف از 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;

کد تماس است

/// <reference path="react/react-addons.d.ts" />
import React = require("react/addons");
import App = require("app");

React.render(App({}), document.getElementById("jsapp"));

کامپوننت به همان صورتی که انتظار دارم رندر میشود اما متدهای handleClick و handleChange وضعیت را به درستی بهروزرسانی نمیکنند. اگر در این دو متد و render نقاط توقف (breakpoint) قرار دهم، مقادیر زیر را برای this میبینم:

  • render: this یک شیء Tester است (همان چیزی که انتظار داشتم).
  • handleChange: this یک ReactClass.createClass.Constructor است.
  • handleClick: this به شیء Window اشاره دارد.

دو مورد آخر به این معناست که شیء وضعیت در دسترس نیست.

هر پیشنهادی با کمال میل پذیرفته میشود.

پاسخ شماره ۱

شما باید متدها را با this متصل کنید زیرا از React.createClass استفاده نمیکنید که این کار را به طور خودکار انجام میدهد. مثال با نحو کلاس:

class Counter extends React.Component {
  constructor() {
    super();
    this.handleChange = this.handleChange.bind(this);
    this.handleClick = this.handleClick.bind(this);
  }
  handleChange() {
    ...
  }
  handleClick() {
    ...
  }
}

پاسخ شماره ۲

شما باید روش رندر خود را تغییر دهید:

render() {
    // ...
        <button onClick={this.handleClick.bind(this)}>Like</button>
        <input value={this.state.name} onChange={this.handleChange.bind(this)} />
    // ...
}

از آنجا که شما یک رویداد را فراخوانی میکنید، کلیدواژه this به زمینه پیشفرض رویداد تغییر خواهد کرد. با استفاده از .bind(this) شما اطمینان حاصل میکنید که زمینهای که فراخوانی میشود، نمونهای از کلاس شما خواهد بود.

پاسخ شماره ۳

روش دیگر استفاده از توابع فلش چاق برای کنترلکنندههای رویداد است که پیوند خودکار «this» را دریافت میکنند.

 handleClick = (evt, domNode):void => {
     this.setState({ liked: !this.state.liked, name: this.state.name });
 };

 <button onClick={() => this.handleClick()}>Like</button>