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'));
これで、今回のカウンターアプリの作成は完了です。
この記事が気に入ったらサポートをしてみませんか?