React.Componentでクラスの状態を管理しよう

前回、作成したクラスをもとにカウンターの中身を実装していきましょう。

カウントの中身を実装しましょう。(src/app.js)

class Counter extends React.Component {
 constructor() {
   super();
   this.count = 0;
 }
 handleAddOne() {
   this.count ++;
   console.log('handleAddOne', this.count);
 }
 handleMinusOne() {
   this.count --;
   console.log('handleMinusOne', this.count);
 }
 handleReset() {
   this.count = 0;
   console.log('handleReset', this.count);
 }
 render() {
   return (
     <div>
       <h1>Count: {this.count}</h1>
       <button onClick={this.handleAddOne}>+1</button>
       <button onClick={this.handleMinusOne}>-1</button>
       <button onClick={this.handleReset}>reset</button>
     </div>
   );
 }
}
ReactDOM.render(<Counter />, document.getElementById('app'));


これで、一見、上手くいくように見えるのですが、ボタンを押すとエラーが出ます。これはhandleAddOne関数からは、countプロパティにアクセスできないためです。

アクセス権を解決しよう

アクセス権を設定してあげましょう。constructorにbindを設定します。

 constructor() {
   super();
   this.count = 0;
   this.handleAddOne = this.handleAddOne.bind(this);
   this.handleMinusOne = this.handleMinusOne.bind(this);
   this.handleReset = this.handleReset.bind(this);
 }

今度は、上手くいきました。

状態を変更できるようにしよう

でも、まだh1タグの中身が更新されていません。これを解決しましょう。

Reactはstateという変数に、今の状態を保持します。それを使いましょう。
コンストラクタの値を書き換えてやります。

   this.state = {
     count: 0
   };

また、現在の値を変更するために、setStateという関数を使います。

  handleAddOne() {
   this.setState(() => {
     return {
       count: this.state.count + 1
     };
   });
 }
 handleMinusOne() {
   this.setState(() => {
     return {
       count: this.state.count - 1
     };
   });
 }
 handleReset() {
   this.setState(() => {
     return {
       count: 0
     };
   });
 }

全体のソースコードは、このようになっています。(src/app.js)

この状態でボタンをクリックすると、<h1>タグの中身を変更されるはずです。

class Counter extends React.Component {
 constructor() {
   super();
   this.state = {
     count: 0
   };
   this.handleAddOne = this.handleAddOne.bind(this);
   this.handleMinusOne = this.handleMinusOne.bind(this);
   this.handleReset = this.handleReset.bind(this);
 }
 handleAddOne() {
   this.setState(() => {
     return {
       count: this.state.count + 1
     };
   });
 }
 handleMinusOne() {
   this.setState(() => {
     return {
       count: this.state.count - 1
     };
   });
 }
 handleReset() {
   this.setState(() => {
     return {
       count: 0
     };
   });
 }
 render() {
   return (
     <div>
       <h1>Count: {this.state.count}</h1>
       <button onClick={this.handleAddOne}>+1</button>
       <button onClick={this.handleMinusOne}>-1</button>
       <button onClick={this.handleReset}>reset</button>
     </div>
   );
 }
}
ReactDOM.render(<Counter />, document.getElementById('app'));

バグを修正しよう

完成したように見えますが、まだ、バグが残っています。

handleResetの実装を以下のように変更して、resetボタンを押下して見て下さい。countの値が増え続けるはずです。一度、0を設定しているから、常に値は1が表示されて欲しいのに、そうなっていません。これは2つの処理が非同期通信で行われているためで、この2つの処理は順番には行われていません。
この問題を修正しましょう。

  handleReset() {
   this.setState(() => {
     return {
       count: 0
     };
   });
   this.setState(() => {
     return {
       count: this.state.count + 1
     };
   });
 }

このように実装することで、prevStateには一つ前のstateの値が入っています。今回は、何度、resetを押下しても値は常に「1」になっているはずです。

  handleReset() {
   this.setState(() => {
     return {
       count: 0
     };
   });
   this.setState((prevState) => {
     return {
       count: prevState.count + 1
     };
   });
 }

他の関数に、prevStateを実装しましょう。(src/app.js)

class Counter extends React.Component {
 constructor() {
   super();
   this.state = {
     count: 0
   };
   this.handleAddOne = this.handleAddOne.bind(this);
   this.handleMinusOne = this.handleMinusOne.bind(this);
   this.handleReset = this.handleReset.bind(this);
 }
 handleAddOne() {
   this.setState((prevState) => {
     return {
       count: prevState.count + 1
     };
   });
 }
 handleMinusOne() {
   this.setState((prevState) => {
     return {
       count: prevState.count - 1
     };
   });
 }
 handleReset() {
   this.setState(() => {
     return {
       count: 0
     };
   });
 }
 render() {
   return (
     <div>
       <h1>Count: {this.state.count}</h1>
       <button onClick={this.handleAddOne}>+1</button>
       <button onClick={this.handleMinusOne}>-1</button>
       <button onClick={this.handleReset}>reset</button>
     </div>
   );
 }
}
ReactDOM.render(<Counter />, document.getElementById('app'));

これで、今回のカウンターアプリの作成は完了です。

この記事が気に入ったらサポートをしてみませんか?