React’s setState methode met prevState argument

Ik ben nieuw bij React, ik heb alleen een vraag over de setState-methode. Laten we zeggen dat we een component hebben:

class MyApp extends React.Component {
  state = {
    count: 3
  };
  Increment = () => {
    this.setState((prevState) => ({
      options: prevState.count + 1)
    }));
  }
}

dus waarom moeten we prevState gebruiken in de setState-methode? waarom kunnen we niet gewoon doen:

this.setState(() => ({
  options: this.state.count + 1)
}));

Antwoord 1, autoriteit 100%

Beide handtekeningen kunnen worden gebruikt, het enige verschil is dat als u uw status moet wijzigen op basis van de vorige status, u this.setState(function)moet gebruiken, waarmee u een momentopname krijgt (prevState) van de vorige staat. Maar als de wijziging niet afhankelijk is van een andere eerdere waarde, wordt een kortere versie aanbevolen this.setState({prop: newValue})

this.setState(prevState =>{
   return{
        ...prevState,
        counter : prevState.counter +1
   }
})
this.setState({counter : 2})

Antwoord 2, autoriteit 65%

class MyApp extends React.Component {
  state = {
    count: 0
  };
  Increment = () => {
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
  };
  IncrementWithoutPrevState = () => {
    this.setState(() => ({
      count: this.state.count + 1
    }));
    this.setState(() => ({
      count: this.state.count + 1
    }));
    this.setState(() => ({
      count: this.state.count + 1
    }));
    this.setState(() => ({
      count: this.state.count + 1
    }));
  };
  render() {
    return (
      <div>
        <button onClick={this.IncrementWithoutPrevState}>
          Increment 4 times without PrevState
        </button>
        <button onClick={this.Increment}>
          Increment 4 times with PrevState
        </button>
        <h1>Count: {this.state.count}</h1>
      </div>
    );
  }
}

Ik heb zojuist een voorbeeld voor je gemaakt om een idee te geven wat wordt bedoeld met “React may batch multiple setState()…” en waarom we prevState in het bovenstaande scenario moeten gebruiken.

Probeer eerst te radenwat het resultaat moet zijn van countwanneer u op beide knoppen klikt… Als u denkt dat de countwordt met 4 verhoogd bij het klikken op beide knoppen, dan is het niet juist;)

Waarom? omdatin de methode IncrementWithoutPrevStateomdat er meerdere setState-aanroepen zijn, dus React heeft al die aanroepen gegroepeerd en de statebijgewerkt alleen in de laatste aanroep van setStatein deze methode, dus op het moment van de laatste aanroep van setStatein deze methode is this.state.countnog niet bijgewerkt en de waarde is nog steeds dezelfde die was voordat de methode IncrementWithoutPrevStatewerd ingevoerd, dus de resulterende status bevat countverhoogd met 1.

Aan de andere kant, als we de Increment-methode analyseren:
Nogmaals zijn er meerdere setStateoproepen en reageer ze allemaal dat ze allemaal betekent dat de werkelijke toestand zal worden bijgewerkt in de laatste oproep van setStatemaar de prevStateWill Bevat altijd de gewijzigde statein de recente setStateCALL. Als previousState.countWaarde is al 3 keer verhoogd totdat de laatste oproep van setStatedus de resulterende statebevat de telwaarde die wordt verhoogd door 4 .


Antwoord 3, Autoriteit 10%

Hier is ISEAWYONE KENNEN ENKEL JUIST: PREVSTATE.COUNTER + 1 .. We kunnen dit ook met staat doen: This.State.Counter + 1. Dit is niet de manier waarop ik denk te gebruiken. Ik heb een probleem in de array wanneer ik in de bestaande staat duwt, waardoor ik me de tweede keer voorkomt, voorkomt het veranderingen


Antwoord 4

Als u een functie meerdere keren belt om de waarde van een staatsobject in een enkele render()Functie-oproep, gaat de bijgewerkte waarde niet over tussen de verschillende oproepen zonder het prevaluerende mechanisme.

second(){
   this.setState({ // no previous or latest old state passed 
       sec:this.state.sec + 1
     }, ()=>{
        console.log("Callback value", this.state.sec)
   })    
}
fiveSecJump(){ // all this 5 call will call together  
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 0 then it will update sec = 0 +1
   }
  render() {
        return (
            <div>
              <div>  Count - {this.state.sec}</div>
              <button onClick ={()=>this.fiveSecJump()}>Increment</button>
            </div>
        )
    }

Uiteindelijk is de sec-waarde 1, omdat aanroepen async zijn, niet zoals programmeertaal op hoog niveau zoals c++/c# of java, waar er altijd een hoofdfunctie is die de hoofdthread onderhoudt.
Dus als je de functie fiveSecJump()goed wilt laten werken, moet je het helpen door er een pijlfunctie aan door te geven. vorigeStaat. prevState is geen trefwoord of lidfunctie, u kunt hier elk woord schrijven, zoals oldState, stackTopState, lastState. Het wordt geconverteerd naar een generieke functie die het gewenste werk zal doen.

class Counter extends Component {
   constructor(props){
        super(props)
        this.state = {
            sec:0
        }
   }
   second(){
        this.setState(prevState =>({
            sec:prevState.sec + 1
        }))
   }
   fiveSecJump(){
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 1 then it will update sec = 1 +1
       this.second() // this call found sec = 2 then it will update sec = 2 +1
       this.second() // this call found sec = 3 then it will update sec = 3 +1
       this.second() // this call found sec = 4 then it will update sec = 4 +1
   }
    render() {
        return (
            <div>
              <div>  Count - {this.state.sec}</div>
              <button onClick ={()=>this.fiveSecJump()}>Increment</button>
            </div>
        )
    }
}
export default Counter

Antwoord 5

//Here is the example to explain both concepts:
import React, { Component } from 'react'
export default class Counter extends Component {
    constructor(props) {
        super(props);
        this.state = { counter: 0 }
    }
    increment() {
        this.setState({counter:this.state.counter+1})
    }
    increment3() {
        this.increment();
        this.increment()
        this.increment()
    }
   render() {
        return (
            <div>
               count-{this.state.counter}
                <div>
                    <button onClick={() => this.increment3()}>Increment</button>
                </div>
            </div>
        )
    }
}

Als we in dit scenario op de knop Verhogenklikken, wordt de uitvoer in de gebruikersinterface weergegeven als count-0en niet count-3omdat react alle statusaanroepen in een enkele statusaanroep groepeert en niet de bijgewerkte waarde over elke verhoogde aanroep draagt. Als ik de waarde wil bijwerken op basis van de vorige waarde, gebruik dan onderstaande code.

import React, { Component } from 'react'
export default class Counter extends Component {
    constructor(props) {
        super(props);
        this.state = { counter: 0 }
    }
    increment() {
        this.setState((prevState=>({counter:prevState.counter+1})))
    }
    incremental() {
        this.increment();
        this.increment()
        this.increment()
    }
   render() {
        return (
            <div>
               count-{this.state.counter}
                <div>
                    <button onClick={() => this.incremental()}>Increment</button>
                </div>
            </div>
        )
    }
}

In dit scenario is de uitvoer count-3en niet count-0


Antwoord 6

@samee’s antwoord was geweldig en heeft me geholpen. Ik wilde dit onderwerp nieuw leven inblazen om React Function Components aan te pakken, simpelweg omdat ik dat momenteel bestudeer.

Het volgende is een voorbeeld van waarom u prevState zou willen gebruiken als de nieuwe status wordt berekend met de vorige status.

function App() {
  const [developer, setDeveloper] = useState({
    yearsExp: 0,
  });
  function handleYearsExp() {
    setDeveloper((prevState) => ({
      yearsExp: prevState.yearsExp + 1, //increments by 1
    }));
    setDeveloper((prevState) => ({
      yearsExp: prevState.yearsExp + 1, //increments by another 1
    }));
  }
  return (
    <>
      <button onClick={handleYearsExp}>Increment Years</button> {/* will increment by 2 */}
      <p>
        I am learning ReactJS and I have {developer.yearsExp} years experience
      </p>
    </>
  );
}

Hier is de code zonder de functie prevStatedie is doorgegeven aan setState. Merk op dat de eerste functie setStatein wezen wordt genegeerd.

function App() {
  const [developer, setDeveloper] = useState({
    yearsExp: 0,
  });
  function handleYearsExp() {
    setDeveloper({
      yearsExp: developer.yearsExp + 1, // is ignored
    });
    setDeveloper({
      yearsExp: developer.yearsExp + 1, //increments by 1
    });
  }
  return (
    <>
      <button onClick={handleYearsExp}>Increment Years</button> {/* will only increment by 1 */}
      <p>
        I am learning ReactJS and I have {developer.yearsExp} years experience
      </p>
    </>
  );
}

Referenties:

  1. ReactJS.org – “Geef een functie door aan setState”
  2. ReactJS.org – “Reageren kan batch meerdere setState()-aanroepen in een enkele update voor prestaties.

Other episodes