import React, { Component } from 'react';
class Counter extends Component {
state = { value: 0 };
increment = () => {
this.setState(prevState => ({
value: prevState.value + 1
}));
};
decrement = () => {
this.setState(prevState => ({
value: prevState.value - 1
}));
};
render() {
return (
<div>
{this.state.value}
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
</div>
)
}
}
通常、私が見たのは、es6 クラスを使用している場合、コンストラクター関数内で this.state を実行する人々です。そうでない場合は、getinitialstate 関数を使用して状態を設定している可能性があります。ただし、上記のコード (はい、動作するコードです) では、どちらも使用されていません。2 つの質問があります。ここでの状態とは何ですか? これはローカル変数ですか? そうである場合、なぜありませんかconst
? prevState はどこから来るのですか? setState で矢印関数が使用されるのはなぜですか? 簡単に実行できないのですかthis.setState({value:'something'})
?
ベストアンサー1
質問が2つあります。
state
ここには何があるのでしょうか?
インスタンスプロパティ、this.state = {value: 0};
コンストラクタでの設定のようなもの。パブリッククラスフィールドの提案increment
現在、ステージ 2 です。(と も同様ですdecrement
。これらはインスタンス フィールドであり、その値は矢印関数であるため、 の上に閉じますthis
。)
それはローカル変数ですか?
いいえ。
prevState はどこから来るのでしょうか? setState で矢印関数が使用されるのはなぜですか? this.setState({value:'something'}) を実行するのは簡単ではないのでしょうか?
からドキュメント:
React は
setState()
パフォーマンスのために、複数の呼び出しを 1 つの更新にまとめる場合があります。
this.props
および は非同期的に更新される可能性があるためthis.state
、次の状態を計算する際にそれらの値に依存しないでください。たとえば、次のコードではカウンターの更新に失敗する可能性があります。
// Wrong this.setState({ counter: this.state.counter + this.props.increment, });
これを修正するには、オブジェクトではなく関数を受け入れる の 2 番目の形式を使用します
setState()
。その関数は、最初の引数として以前の状態を受け取り、2 番目の引数として更新が適用された時点のプロパティを受け取ります。// Correct this.setState((prevState, props) => ({ counter: prevState.counter + props.increment }));
...これはまさに引用したコードが行っていることです。これは間違いです:
// Wrong
increment = () => {
this.setState({
value: this.state.value + 1
});
};
... は の状態に依存しているためですがthis.state
、上記ではそうしないように指示されています。そのため、引用されたコードは代わりにこれを行います。
increment = () => {
this.setState(prevState => ({
value: prevState.value + 1
}));
};
Reactがわかりにくい方法でバッチ呼び出しを行う可能性があることと、のコールバックバージョンを使用する必要がある理由の証拠を以下に示します。setState
ここでは、increment
およびdecrement
が呼び出されます。2回1回のクリックではなく、1回のクリック(ボタンごとに1回、ボタンを含むスパンごとに1回)です。+
一度は 2 回呼び出されるため、カウンタを 2 に増やす必要がありますincrement
。しかし、 の関数コールバック バージョンを使用していないためsetState
、そうはなりません。 の呼び出しの 1 つは、increment
古い値を使用しているため、何も実行されませんthis.state.value
。
class Counter extends React.Component {
state = { value: 0 };
increment = () => {
/*
this.setState(prevState => ({
value: prevState.value + 1
}));
*/
console.log("increment called, this.state.value = " + this.state.value);
this.setState({
value: this.state.value + 1
});
};
fooup = () => {
this.increment();
};
decrement = () => {
/*
this.setState(prevState => ({
value: prevState.value - 1
}));
*/
console.log("decrement called, this.state.value = " + this.state.value);
this.setState({
value: this.state.value - 1
});
};
foodown = () => {
this.decrement();
};
render() {
return (
<div>
{this.state.value}
<span onClick={this.fooup}>
<button onClick={this.increment}>+</button>
</span>
<span onClick={this.foodown}>
<button onClick={this.decrement}>-</button>
</span>
</div>
)
}
}
ReactDOM.render(
<Counter />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
関数コールバックを使用すると、正しく動作します ( increment
no-ops になる呼び出しはありません)。
class Counter extends React.Component {
state = { value: 0 };
increment = () => {
this.setState(prevState => {
console.log("Incrementing, prevState.value = " + prevState.value);
return {
value: prevState.value + 1
};
});
};
fooup = () => {
this.increment();
};
decrement = () => {
this.setState(prevState => {
console.log("Decrementing, prevState.value = " + prevState.value);
return {
value: prevState.value - 1
};
});
};
foodown = () => {
this.decrement();
};
render() {
return (
<div>
{this.state.value}
<span onClick={this.fooup}>
<button onClick={this.increment}>+</button>
</span>
<span onClick={this.foodown}>
<button onClick={this.decrement}>-</button>
</span>
</div>
)
}
}
ReactDOM.render(
<Counter />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
この場合、もちろん、render
メソッドを見て「increment
クリック中に2回呼び出されるので、のコールバックバージョンを使用する方が良いsetState
」と言うことができます。しかし、次の状態を決定するときに使用しても安全であると想定するのではなくthis.state
、ベストプラクティスは次のとおりです。ないそれを前提としています。複雑なコンポーネントでは、ミューテーター メソッドの作成者が考えていなかった方法でミューテーター メソッドを使用することは簡単です。そのため、React の作成者は次のように述べています。
this.props
およびは非同期的に更新される可能性があるためthis.state
、次の状態を計算するためにそれらの値に頼るべきではない。