web-dev-qa-db-ja.com

React Native:this.setStateは関数ではありません

この同じ問題に関連する質問がここにたくさんありますが、私が抱えている問題と一致するものはないようで、もう少し複雑です。

私は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>
    );
  }
}
23
William C

レンダー内でバインドを使用しないでください。バインドはかなり高価な操作であり、一度だけ実行する必要があります。次の2つのオプションがあります。

コンストラクターで関数をバインドします。

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

または、矢印関数を使用します。

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

編集

どうやらレンダー内の矢印関数も悪い習慣です(以下のコメントと回答のAdam TerlsonへのThx)。 eslint docs を読むことができます。

JSXプロップのバインド呼び出しまたは矢印関数は、レンダリングごとに新しい関数を作成します。ガベージコレクターが必要以上に呼び出されるため、これはパフォーマンスに悪影響を及ぼします。

矢印関数の使用は明らかにバインドの使用ほど悪くはありませんが、それでも避けるべきです。

42
atlanteh

矢印関数に関しては、_handleTextChange(event)関数も変更する必要があります。他の回答では、通常の機能を矢印機能に変更する方法については言及していませんでした。だから、他の人を助けるかもしれない答えとして提供する

ハンドラー関数を変更する必要があります

から

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

_handleTextChange = event => {
   this.setState({Zip: event.nativeEvent.text});
 }
12
Hemadri Dasari

ここでの他のコメントと回答で特定されているように、問題はコンテキストバインディングです。

ただし、バインド自体のパフォーマンスは問題ではありません。より関連性のある問題は、レンダリングメソッドでバインドまたは矢印を使用すると、各レンダリングで新しい関数が作成されるため、それらを受け取る子は、再レンダリングを強制します。

次の2つの実行可能なオプションがあります。

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

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

または、 babel plugin を使用している場合は、クラスプロパティ表記を使用して矢印関数を割り当てることができます。

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

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

react Recommended Rules を有効にしてeslintパッケージを使用することを強くお勧めします。レンダーでバインド/矢印を使用するなどのエラーをキャッチするだけでなく、アンダースコアの接頭辞付き関数はfunctionsいため、Reactではまったく必要ないことを伝えます。 :)

7
Adam Terlson