web-dev-qa-db-fra.com

React gestionnaires d'événements avec TypeScript et JSX

J'ai des problèmes pour mettre à jour l'état dans un composant React que j'écris en TypeScript (React with Addons 0.13.3, TypeScript 1.6.0-dev.20150804, fichier de définition 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;

Le code d'appel est

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

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

Le composant s'affiche comme prévu, mais les méthodes handleClick et handleChange ne mettent pas l'état à jour correctement. Si je mets des points d'arrêt dans ces deux méthodes et render alors je vois les valeurs suivantes pour this:

  • render: this est un objet Tester (ce que j'attendrais).
  • handleChange: this est un ReactClass.createClass.Constructor.
  • handleClick: this est une référence à l'objet Window.

Les deux derniers signifient que l'objet d'état n'est pas disponible.

Toutes les suggestions reçues avec reconnaissance.

18
Ian G

Vous devez changer votre méthode de rendu:

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

Puisque vous appelez un événement, le mot-clé this sera remplacé par le contexte par défaut de l'événement. En utilisant .bind(this) vous vous assurez que le contexte appelé sera l'instance de votre classe.

11
Buzinas

Vous devez lier des méthodes avec this car vous n'utilisez pas React.createClass qui le fait automatiquement. Exemple avec une syntaxe de classe:

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

Une autre méthode consiste à utiliser les fonctions de flèche grasse pour les gestionnaires d'événements qui obtiennent automatiquement "cette" liaison.

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

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