2016-07-18 193 views
11

Vedo un numero di domande su questo stesso problema, ma sembra che nessuno corrisponda al problema che sto avendo e sia un po 'più complesso.React Native: this.setState non è una funzione

Sono in procinto di apprendere ReactJS e React Native. Sono nel bel mezzo della lettura e seguendo gli esempi di codice del libro "Learning React Native" qui: https://github.com/bonniee/learning-react-native

Per qualche motivo, chiamare this.setState nel codice seguente quando viene chiamata la funzione handleTextChange, causa "questo .SetState non è una funzione. " errore. La mia domanda è perché? A differenza di altre domande su questo stesso problema, non credo che la mia chiamata a this.StateState sia sepolta in una funzione di callback o in una dichiarazione. Perché è indefinito?

Ecco il mio codice:

class WeatherProject extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     zip: "", 
     forecast: null 
    }; 
    } 

    _handleTextChange(event) { 
    this.setState({zip: event.nativeEvent.text}); 
    } 

    render() { 
    return (
     <View style={styles.container}> 
     <Text style={styles.welcome}> 
     You input {this.state.zip}. 
     </Text> 
     <TextInput 
     style={styles.input} 
     onSubmitEditing={this._handleTextChange}/> 
     </View> 
    ); 
    } 
} 
+5

'onSubmitEditing = {this._handleTextChange.bind (this)} />', o 'onSubmitEditing = {() => questo._handleTextChange()} /> ' –

+0

@AlexanderT. Ha funzionato alla grande, grazie. Quindi, perché ho bisogno di legarlo a quel gestore pari? –

+0

È possibile visualizzare questo articolo: https://medium.com/@razgoldin/using-react-es-6-syntax-fc05acf72810#.rab7bgxnw – Zargold

risposta

26

Non utilizzare legano all'interno di un rendering. legare è un'operazione piuttosto costosa e dovrebbe accadere solo una volta. avete due opzioni:

sia legano la funzione nel costruttore:

this._handleTextChange = this._handleTextChange.bind(this); 

o utilizzare la funzione freccia:

onSubmitEditing={(e) => this._handleTextChange(e)} /> 

Modifica

Apparentemente freccia funzioni all'interno rendono è anche una cattiva pratica (da Thx a Adam Terlson nei commenti e risposta sotto). È possibile leggere eslint docs che indica:

Una chiamata di bind o una funzione di freccia in un puntello JSX creerà una nuova funzione su ogni singolo rendering. Ciò non è positivo per le prestazioni, poiché il garbage collector viene richiamato molto più del necessario.

Utilizzare le funzioni di freccia non è ovviamente così grave come utilizzare il binding, ma deve essere evitato.

+1

o la funzione proposta ES7, ':: this._handleTextChange' – ZekeDroid

+0

L'impatto sulle prestazioni di causare un ri-rendering non necessario sul componente figlio utilizzando una freccia nella funzione di rendering è probabilmente un ordine di grandezza peggiore delle prestazioni della funzione 'bind' stessa. –

+0

Non ho mai sentito parlare di una cosa del genere. Ogni tutorial là fuori è incoraggiante nell'uso delle funzioni di freccia invece del binding. puoi per favore fornire una fonte per quello che stai dicendo? – atlanteh

5

Il problema è legato al contesto, come identificato negli altri commenti e nelle risposte qui.

Tuttavia, le prestazioni del bind stesso non sono un problema. La questione più rilevante è che l'uso del binding o delle frecce nei metodi di rendering crea una nuova funzione su ogni rendering, determinando una modifica degli oggetti di scena per il bambino che li riceve, forzando un nuovo rendering.

Hai due opzioni praticabili:

class WeatherProject extends Component { 
    constructor(props) { 
    super(props); 

    this._handleTextChange = this._handleTextChange.bind(this); 
    } 
    // ... 
} 

Oppure si può usare la notazione di classe e assegnare le funzioni di direzione se si sta utilizzando il babel plugin per esso.

class WeatherProject extends Component { 
    constructor(props) { 
    super(props); 
    // ... 
    } 

    handleTextChange = (event) => { 
    this.setState({zip: event.nativeEvent.text}); 
    } 
    // ... 
} 

vi consiglio caldamente di utilizzare il pacchetto eslint con il react recommended rules abilitato. Cattura errori come l'uso di bind/frecce nel rendering, oltre a dirti che le funzioni di prefisso sottolineatura sono brutte e totalmente non necessarie in React. :)

+0

In realtà secondo eslint [docs] (https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md), l'unico problema è creare una funzione nuova di zecca in ogni chiamata, che è un male per le prestazioni, ma non causa il re-rendering di un figlio – atlanteh

+0

@atlanteh Sì, questo è vero ma il mio punto più ampio è ancora valido. Questo è solo uno dei tanti articoli che fanno riferimento al problema del cambiamento prop. https://medium.com/@esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f?source=linkShare-583b3a685d22-1481269421 –

+0

Vero, è per questo che ho aggiornato la mia risposta :) – atlanteh