CodeZine(コードジン)

特集ページ一覧

Reactの基本を学ぼう~コンポーネントで動的な状態管理

基礎からはじめるReact Native入門 第4回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2019/10/15 11:00
目次

ユーザー操作のイベントを使って状態を更新する

 それでは、stateの具体的な使い方について例を挙げていきましょう。まずはユーザー操作を受け付けて状態を変更する方式をサンプルにします。単純なほうがよいので、ボタンを押すと数字が増減するカウンターアプリにしてみましょう(図2)。

図2:カウンターアプリ
図2:カウンターアプリ

 ソースコードはリスト6のとおりです。

[リスト6]カウンターアプリ
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';

export default class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      count: 0,
    }
  }

  onPressMinusOne = () => {
    this.setState({ count: this.state.count - 1 }); // (2)
  };

  onPressPlusOne = () => {
    this.setState({ count: this.state.count + 1 }); // (3)
  }

  render() {
    return (
      <View style={styles.container}>
        <Button title="-1" onPress={this.onPressMinusOne} />{/* (1) */}
        <Text>{this.state.count}</Text>
        <Button title="+1" onPress={this.onPressPlusOne} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  }
});

 React Native標準のButtonコンポーネントを使ってみました。React Nativeはモバイルアプリ開発のツールである都合上、画面はクリックするものではなくタップするものという前提があります。そのため、タップイベントを受け取るためのpropsの名前はonclickonClickではなく、onPressになっています。

 onPressは関数オブジェクトを受け取るpropsです。(1)のように、関数オブジェクトを登録しておくと、タップイベントが発生したときにその関数が実行されます。今回の例ではクラスのプロパティであるonPressMinusOneonPressPlusOneを実行するようにしてみました。その内部では(2)や(3)のようにsetStateを呼び出しており、ボタン操作によってstateを更新する流れが作られています。

関数を扱うpropsの注意点

 リスト6では、クラス内の関数の定義とJSXの組み合わせが、リスト7のようになっていました。

[リスト7]クラスのプロパティとして関数を登録する
// 関数定義
onPressMinusOne = () => {
  this.setState({ count: this.state.count - 1 });
};
// JSX
<Button title="-1" onPress={this.onPressMinusOne} />

 この関数定義は、ECMAScriptのクラスにおけるメソッド定義の文法ではなく、プロパティにラムダ記法で記述された関数を代入する式です。本来は、リスト8のような書き方をしたほうが、クラスの使い方として直感的です。

[リスト8]誤った関数オブジェクトの渡し方
// 関数定義
onPressMinusOne() { // (1)
  this.setState({ count: this.state.count - 1 }); // (3)
};
// JSX
<Button title="-1" onPress={this.onPressMinusOne} /> // (2)

 では、なぜリスト7のような面倒なことをしているのかというと、リスト8の書き方は意図しない動作をする可能性があるからです。

 実は、(1)のようにクラス内に定義されたメソッドであっても、その中で使われるthisの参照先は実行方法によって変わってしまうのです。(2)のように関数オブジェクトをそのまま渡すと、実行時に(3)がthisとして参照するのはButtonコンポーネントになります。そのため、リスト8の形で実装したアプリを起動して、マイナスボタンを押すと、図3のようなエラーが発生します。

図3:thisの参照ミスによりエラーが発生する
図3:thisの参照ミスによりエラーが発生する

 図3上部の赤いところを参考にして状況を読み取ってみると、Buttonコンポーネントの中にthis.stateが存在しない、つまりundefinedなので、その中のcountを参照しようとした時点でエラーになる、ということです。これはReactの仕組み上そうなっているわけではなく、ECMAScriptのクラス記法の標準的な仕組みで起こる課題です。

 どうしてもメソッド記法を使いたい場合は、リスト9のように記述することができます。

[リスト9]メソッド記法を使いたい場合
// コンストラクタ
constructor(props) {
  super(props);
  this.onPressMinusOne = this.onPressMinusOne.bind(this); // (1)
}
// 関数定義
onPressMinusOne() {
  this.setState({ count: this.state.count - 1 });
};
// JSX
<Button title="-1" onPress={this.onPressMinusOne} />

 (1)のように事前にthisをバインドしておくことで、thisAppにひも付けておくことができます。しかし面倒なので、ひとまずリスト7の方法を覚えておくとよいでしょう。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:基礎からはじめるReact Native入門

もっと読む

著者プロフィール

  • WINGSプロジェクト 中川幸哉(ナカガワユキヤ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5