web-dev-qa-db-ja.com

setStateメソッドを呼び出してもすぐに状態が変化しないのはなぜですか?

わかりました、簡単に修正できるはずですので、これをすばやく試してみます...

似たような質問をたくさん読みましたが、その答えは非常に明白です。そもそも見上げる必要はありません!しかし...私は、修正方法やその理由を推測できないエラーを抱えています。

次のように:

_class NightlifeTypes extends Component {
constructor(props) {
    super(props);

    this.state = {
        barClubLounge: false,
        seeTheTown: true,
        eventsEntertainment: true,
        familyFriendlyOnly: false
    }
    this.handleOnChange = this.handleOnChange.bind(this);
}

handleOnChange = (event) => {   
    if(event.target.className == "barClubLounge") {
        this.setState({barClubLounge: event.target.checked});
        console.log(event.target.checked)
        console.log(this.state.barClubLounge)
    }
}

render() {
    return (
        <input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>
    )
}
_

より多くのコードがこれを囲んでいますが、これが私の問題のあるところです。動作するはずですよね?

私もこれを試しました:

_handleOnChange = (event) => {   
if(event.target.className == "barClubLounge") {
    this.setState({barClubLounge: !this.state.barClubLounge});
    console.log(event.target.checked)
    console.log(this.state.barClubLounge)
}
_

そのため、これら2つのconsole.log()があり、両方とも同じでなければなりません。文字通り、状態をその上の行の_event.target.checked_と同じに設定しています!

しかし、それは常に本来の反対を返します。

_!this.state.barClubLounge_を使用する場合も同様です。 falseで始まる場合、チェックボックスがチェックされているかどうかは状態に基づいていても、最初のクリックではfalseのままです!!

それは狂ったパラドックスであり、私は何が起こっているのか分かりません、助けてください!

40
Dan

理由はsetStateは非同期ですstateメソッドを使用して値を確認する場合は、setStateの直後に更新されたcallback値を期待できません。 setStateがタスクを完了した後に実行されるメソッドをコールバックとして渡します。

SetStateが非同期なのはなぜですか?

これは、setStatestateを変更し、再レンダリングを引き起こすためです。これは高価な操作になる可能性があり、synchronousにするとブラウザが応答しなくなる場合があります。したがって、setState呼び出しは、asynchronousであり、UIエクスペリエンスとパフォーマンスを向上させるためにバッチ処理されます。

From Docから:

setState()はすぐにthis.stateを変更しませんが、保留状態遷移を作成します。このメソッドを呼び出した後にthis.stateにアクセスすると、既存の値が返される可能性があります。 setStateの呼び出しの同期操作の保証はなく、パフォーマンス向上のために呼び出しをバッチ処理できます。

setStateでのコールバックメソッドの使用:

stateの直後の更新されたsetState値を確認するには、次のようなコールバックメソッドを使用します。

setState({ key: value }, () => {
     console.log('updated state value', this.state.key)
})

これをチェックして:

class NightlifeTypes extends React.Component {
   constructor(props) {
      super(props);

      this.state = {
         barClubLounge: false,
         seeTheTown: true,
         eventsEntertainment: true,
         familyFriendlyOnly: false
      }
   }

   handleOnChange = (event) => {  // Arrow function binds `this`
      let value = event.target.checked;

      if(event.target.className == "barClubLounge") {

         this.setState({ barClubLounge: value}, () => {  //here
             console.log(value);
             console.log(this.state.barClubLounge);
             //both will print same value
         });        

      }
   }

   render() {
      return (
          <input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>
      )
   }
}

ReactDOM.render(<NightlifeTypes/>, document.getElementById('app'))
<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>

<div id='app'/>
47
Mayank Shukla

SetStateは非同期関数であるため。つまり、setState状態変数を呼び出した後、すぐには変更されません。したがって、状態を変更した直後に他のアクションを実行する場合は、setState更新関数内でsetstateのコールバックメソッドを使用する必要があります。

handleOnChange = (event) => { 
     let inputState = event.target.checked;
      if(event.target.className == "barClubLounge") {
         this.setState({ barClubLounge: inputState}, () => {  //here
             console.log(this.state.barClubLounge);
             //here you can call other functions which use this state 
             variable //
         });        
      }
   }
1
Asif J

これは、パフォーマンスを考慮した設計によるものです。 setState in Reactは関数です保証は、高コストのCPUプロセスであるコンポーネントを再レンダリングします。そのため、設計者は複数のレンダリングアクションをそのため、setStateは非同期です。

0
Nir O.