2015-04-19 14 views
17

Per qualche motivo il valore di questo si sta perdendo nel gestore eventi react. Leggendo la documentazione ho pensato che reagiscono ha fatto un po 'di roba qui per assicurarsi che questo è stato impostato sul valore correttoValore di questo nel gestore eventi React

La seguente non funziona come mi aspetto

import React from 'react'; 

export default class Observer extends React.Component { 

    handleClick() { 
     console.log(this); //logs undefined 
    } 
    render() { 
     return (
      <button onClick={this.handleClick}>Click</button> 
     ); 
    } 
} 

ma questo:

import React from 'react'; 

export default class Observer extends React.Component { 

    handleClick() { 
     console.log(this); //logs Observer class instance 
    } 
    render() { 
     return (
      <button onClick={this.handleClick.bind(this)}>Click</button> 
     ); 
    } 
} 

React e ES6 sono nuovi per me ma questo sembra non essere il comportamento corretto?

+0

Perché non dovrebbe essere un comportamento corretto? Jsx oscura troppo la funzione che stai creando per 'onClick'? – Bergi

+0

Questo non ha nulla a che fare con ES6. Neanche in ES5 funzionerebbe. – Bergi

+0

@Bergi La risposta accettata dice diversamente. In ES5 utilizzeresti [React.createClass] (https://facebook.github.io/react/docs/top-level-api.html#react.createclass) e non dovresti legarti manualmente. Quindi sì, questo ha tutto a che fare con l'OP usando ES6 per creare componenti React. –

risposta

27

Questo comportamento è corretto per JavaScript e Reagire se si utilizza la nuova sintassi class.

autobinding feature does not apply to ES6 classes in v0.13.0.

Quindi è necessario utilizzare:

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

o uno degli altri trucchi:

export default class Observer extends React.Component { 
    constructor() { 
    super(); 
    this.handleClick = this.handleClick.bind(this); 
    } 
    handleClick() { 
    /* ... */ 
    } 
    render() { 
     return <button onClick={this.handleClick}>Click</button> 
    } 
} 
+0

Modificato la risposta per chiarire che l'autobinding continua a funzionare con React.createClass in tutte le versioni di React. –

+0

Grazie per il chiarimento Ben. – WiredPrairie

+1

Si noti che nel documento che si collega si fornisce anche un'altra soluzione che utilizza le proprietà della classe ES7 per creare gestori di funzioni freccia, ex 'handleClick = (e) => {}', quindi nessuna chiamata 'bind' è necessaria nel costruttore o in qualsiasi luogo. – Aaron

10

Come altri hanno detto, Reagire non bind automatico metodi per l'istanza quando si utilizza ES6 classi. Detto questo, vorrei fare l'abitudine di utilizzare sempre le funzioni di direzione in gestori di eventi come: onClick={e => this.handleClick()}

Invece di: onClick={this.handleClick.bind(this)}

Ciò perché significa che è possibile sostituire il metodo handleClick con una spia in un test, qualcosa che si non posso fare quando usi il bind.

+0

Nell'esempio della freccia, il metodo handleClick non ottiene l'elemento DOM come argomento se non lo si inoltra esplicitamente correttamente? –

+0

Esatto, deve essere 'onClick = {e => this.handleClick (e.target)}' per la funzione handleClick per ottenere l'elemento cliccato. –

13

La risposta accettata è buona e l'ho usato molto in ES6, ma voglio solo aggiungere un'altra soluzione "più moderno" che abbiamo con ES7 (menzionato nel React component class auto-binding notes): utilizzare le funzioni di direzione come class properties, allora non hai bisogno di legare o avvolgere il tuo gestore ovunque.

export default class Observer extends React.Component { 
    handleClick = (e) => { 
    /* ... */ 
    } 
    render() { 
     return <button onClick={this.handleClick}>Click</button> 
    } 
} 

Questa è la soluzione più semplice e pulita!

+0

Non 'onClick = {e => this.handleClick (e)}' più efficiente? Credo che sia quasi lo stesso di 'this.handleClick = this.handleClick.bind (this)' eccetto che quest'ultimo è più a doppio tipizzazione. –

+2

Il mio esempio non usa '.bind()', definisce la fat fat come una proprietà di classe e semplicemente la passa nel puntello di callback. Penserei che sia più efficiente della definizione di una funzione di freccia in ogni rendering di un puntello di richiamata, ed è meno digitante, soprattutto se si desidera utilizzare il gestore in più punti nella funzione di rendering. – Aaron