_this2.setState is not a function错误解决办法

编写RN的小伙伴都知道setState是RN最常见的一个函数,但是这个最简单的函数却是经常报错,这一次我们就来解决
_this2.setState is not a function这个错误。

首先来看一下我的代码,这段代码就是发送一个请求,然后在相应回调函数的地方解析出数据修改state内部的值,达到渲染界面的效果:

import React,{Component} from 'react';
import {
    View,
    StyleSheet,
    Button,
    Text
} from 'react-native';

import * as StringUtilsService from '../Utils/StringUtilsService';

import * as InterfaceService from '../Utils/InterfaceService';

export default class StudyComponent extends Component{
    constructor(props){
        super(props);
        this.state = {
            jobName: null,
        };
    }

    render(){
        const { navigate } = this.props.navigation;
        return(
            style={styles.container}>
                

错误的根源就在于onPress哪里应该修改为 onPress={this.login.bind(this)}

原因:这是因为ES6写法,也就是类(Class)的写法,React默认不会自动绑定类中的方法造成的。
React对ES5的语法是默认有自动绑定,所以不需要加这个。

而且,自动绑不绑定也是React决定要不要的


后说缘由:

React的元件从定义开始,到执行完成渲染到真实的DOM元素中,是一个很复杂的过程,这里面也包含了事件处理函式到底是要用什么方式来执行。事件处理函式原本就是一个很特别的回调函式,当在事件触发时是要执行从什么地方来的函式,是在元件自己本身定义的函式(方法)?还是上层元件定义的函式(方法)?或者来自外部的模组或函式?执行的对象又是谁?这些问题都要一起考量。

要讲到函式的this值与上下文(Context),先需要对JavaScript再科普一下,摘要出来在下面说明。在JavaScript中,函式一共有以下四种呼叫的样式,它们分别是:

  • 一般的函式呼叫(Function Invocation Pattern)

  • 物件中的方法呼叫(Method Invocation Pattern)

  • 建构函式呼叫(Constructor Invocation Pattern)

  • 使用apply, call, bind方法呼叫(应用呼叫样式 Apply invocation pattern / 间接呼叫样式 Indirect Invocation Pattern)

对函式库或框架(或是对具熟练技术的开发者)来说,最具弹性的是最后一种,因为它可以提供最多的方便性,以间接的呼叫样式,在必要的时候才进行呼叫,也可以转换函式(方法的)上下文(Context)。当你真正理解为何this值的真正涵义时,你会发现以下几个事实,这可能会颠覆对于JavaScript中函式的原先想像:

"函式定义是定义,呼叫是呼叫": 实际上在物件定义的所谓方法,你可以把它当作只是让开发者方便集中管理的函式定义。

  • this值来说,它根本不关心函式是在哪里定义或是怎么定义的,它只关心是谁呼叫了它。

  • 所有的函式在呼叫时,其实都有一个拥有者物件来进行呼叫"。所以你可以说,其实所有函式都是物件中的"方法。所有的函式执行都是以Object.method()方式呼叫。

回到React中,新版本(0.13后)允许我们可以使用ES6的类(Class)定义方式来定义组件,这称之为"建构函式呼叫样式",但原本的工厂样式(也就是使用React.createClass方法,或称为ES5语法方式)并没有因此而废止不用,也就是说这两种定义方式在基本使用上是可以得到相等结果的,只是里面所使用的语法细节有所不同。对于React来说,实际上它根本也不允许你在使用new来产生ES6+类定义的实体,那它的内部又是如何来呼叫或执行这些我们在类里面定义的方法的?

答案已经很明显了,绝对不是单纯的"建构函式呼叫样式",它在程式码中混用了多种的函式呼叫样式,而且会使用最具弹性的那种"间接的呼叫样式",也就是说它明显的使用了this中"函式定义是定义,呼叫是呼叫"的作法。

在React官方对建构式样式(ES6类别)定义方式与工厂样式(也就是使用React.createClass方法)的说明中,有一个非常大的差异,称为"Autobinding"(自动绑定),工厂样式中的this值是会自动绑定的,但建构式样式(ES6类别)定义方式的this值"不会"再自动绑定。

自动绑不绑定最大的影响会在于当元件的render方法中,在React元素(JSX语法)中呼叫我们定义的函式(方法)时,最早之前版本的工厂样式也不会自动绑定,是后来加入的功能(v0.4, 2013),出自[React官网这里] (https://facebook.github.io/re...

由此得知,自动绑定并非一个JavaScript中的自然内部机制,而是由React自己所决定的的内部实作功能。但在v0.13(2015)版本中取消了ES6类别里面这个机制,理由除了像上面所说的,当在事件触发时要执行的回调函式,来源可能有很多种,对象或许并非单一。另一个主要的理由是为了不让开发者造成混乱,以为在ES6类别里这个机制是自然就有的,所以在建构式样式(ES6类别)后改成了你需要手动绑定。

要绑定类别中的方法(函式)可用下面两种语法,出自React官网这里:

第一种是在建构式中constructor加入绑定你定义的方法的语句:

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

第二种是用箭头函式语法来宣告方法:

class Counter extends React.Component {
  tick = () => {
    //...
  }
  //...
}

要注意的这个语法既非ES6也非ES7,暂且称它为ES7+或ES8,但babel工具可以正确的转译这个语法,所以你不需要担心会有执行上的问题。第二种需要加装babel-plugin-transform-class-properties,并在.babelrc中配置到plugins中,参考https://babeljs.io/docs/plugi...

最后的结论是,JSX是React创的,babel是React养的,自动绑不绑定也是React决定要不要的。

原因是我借鉴的:https://segmentfault.com/q/1010000007247736方便和大家说明问题的根源。

你可能感兴趣的:(ReactNative的那些坑)