React Native:this.setState 不是函数

IT技术 javascript reactjs react-native
2021-04-10 02:05:29

我在这里看到许多与同一问题相关的问题,但似乎没有一个与我遇到的问题相匹配,而且更复杂一些。

我正在学习 ReactJS 和 React Native。我正在阅读和关注“Learning React Native”一书中的代码示例:https : //github.com/bonniee/learning-react-native

出于某种原因,在调用 handleTextChange 函数时在下面的代码中调用 this.setState 会导致“this.SetState 不是函数”。错误。我的问题是为什么?与关于同一问题的其他问题不同,我不相信我对 this.stateState 的调用隐藏在回调函数或 if 语句中。为什么是未定义的?

这是我的代码:

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个回答

不要在渲染中使用绑定。bind 是一个相当昂贵的操作,应该只发生一次。你有两个选择:

要么在构造函数中绑定函数:

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

或使用箭头功能:

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

编辑

显然,渲染中的箭头函数也是一种不好的做法(感谢 Adam Terlson 在下面的评论和回答中)。您可以阅读eslint 文档,其中指出:

JSX props中的绑定调用或箭头函数将在每次渲染时创建一个全新的函数。这对性能不利,因为它会导致垃圾收集器被调用的方式超出必要的范围。

使用箭头函数显然没有使用绑定那么糟糕,但仍然应该避免。

我的评论不支持绑定。它不支持箭头。它表明,无论哪种组件接收您刚刚创建的新函数,都将导致组件 prop 发生更改,这可能会对性能产生巨大影响。
2021-05-29 02:05:29
@atlanteh 当我们使用箭头函数时 _handleTextChange(event) 必须更改为 _handleTextChange = (event) => 不是吗?
2021-05-30 02:05:29
通过在渲染函数中使用箭头对子组件造成不必要的重新渲染的性能影响可能比bind函数本身的性能差一个数量级
2021-06-01 02:05:29
我从来没有听说过这样的事情。每个教程都鼓励使用箭头函数而不是绑定。你能提供你所说的话的来源吗?
2021-06-07 02:05:29
或 ES7 提议的功能, ::this._handleTextChange
2021-06-12 02:05:29

关于箭头功能,您还需要更改_handleTextChange(event)功能。其他答案没有谈到如何将普通功能更改为箭头功能。

您需要更改处理程序函数,从:

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

到:

_handleTextChange = event => {
   this.setState({zip: event.nativeEvent.text});
 }
谢谢,这对我有用。我不明白的是为什么this本地方法中上下文会发生变化,这不应该是维护它上下文的主要地方吗?
2021-06-04 02:05:29

问题是上下文绑定,如此处的其他评论和答案中所述。

但是,bind 本身的性能不是问题。更相关的问题是,在渲染方法中使用绑定或箭头会在每次渲染时创建一个新函数,从而导致接收它们的孩子的props发生变化,从而强制重新渲染。

您有两个可行的选择:

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

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

或者,如果您使用babel 插件您可以使用类属性符号并分配箭头功能

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

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

我强烈建议您使用启用react 推荐规则的 eslint 包它会捕获诸如在渲染中使用绑定/箭头之类的错误,并告诉您下划线前缀函数很丑陋,并且在 React 中完全没有必要。:)

实际上根据 eslint docs,唯一的问题是在每次调用中创建全新的函数,这对性能不利,但不会导致孩子重新渲染
2021-06-06 02:05:29
@atlanteh 是的,这是真的,但我更广泛的观点仍然有效。这只是引用道具更改问题的众多文章之一。medium.com/@esamatti/...
2021-06-12 02:05:29

this.setState 不是函数---用这个解决

 let that = this;

 that.setState({membersArray:response.data})

我在尝试设置状态时遇到了同样的问题。当我在构造函数中绑定函数时,问题就解决了。检查以下绑定

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

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

  }