ReactJS: Waarschuwing: setState(…): kan niet updaten tijdens een bestaande statusovergang

Ik probeer de volgende code te refactoren vanuit mijn weergaveweergave:

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange.bind(this,false)} >Retour</Button>

naar een versie waarbij de binding zich binnen de constructor bevindt. De reden daarvoor is dat binden in de weergaveweergave prestatieproblemen zal opleveren, vooral op low-end mobiele telefoons.

Ik heb de volgende code gemaakt, maar ik krijg constant de volgende fouten (veel). Het lijkt erop dat de app in een lus raakt:

Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.

Hieronder staat de code die ik gebruik:

var React = require('react');
var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');
var Button = require('react-bootstrap/lib/Button');
var Form = require('react-bootstrap/lib/Form');
var FormGroup = require('react-bootstrap/lib/FormGroup');
var Well = require('react-bootstrap/lib/Well');
export default class Search extends React.Component {
    constructor() {
        super();
        this.state = {
            singleJourney: false
        };
        this.handleButtonChange = this.handleButtonChange.bind(this);
    }
    handleButtonChange(value) {
        this.setState({
            singleJourney: value
        });
    }
    render() {
        return (
            <Form>
                <Well style={wellStyle}>
                    <FormGroup className="text-center">
                        <ButtonGroup>
                            <Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange(false)} >Retour</Button>
                            <Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChange(true)} >Single Journey</Button>
                        </ButtonGroup>
                    </FormGroup>
                </Well>
            </Form>
        );
    }
}
module.exports = Search;

Antwoord 1, autoriteit 100%

Het lijkt erop dat u per ongeluk de methode handleButtonChangein uw rendermethode aanroept, u ​​wilt waarschijnlijk onClick={() => this.handleButtonChange(false)}in plaats daarvan.

Als je geen lambda wilt maken in de onClick-handler, denk ik dat je twee gebonden methoden nodig hebt, één voor elke parameter.

In de constructor:

this.handleButtonChangeRetour = this.handleButtonChange.bind(this, true);
this.handleButtonChangeSingle = this.handleButtonChange.bind(this, false);

En in de rendermethode:

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChangeSingle} >Retour</Button>
<Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChangeRetour}>Single Journey</Button>

Antwoord 2, autoriteit 5%

Ik geef een algemeen voorbeeld voor een beter begrip, in de volgende code

render(){
    return(
      <div>
        <h3>Simple Counter</h3>
        <Counter
          value={this.props.counter}
          onIncrement={this.props.increment()} <------ calling the function
          onDecrement={this.props.decrement()} <-----------
          onIncrementAsync={this.props.incrementAsync()} />
      </div>
    )
  }

Bij het leveren van rekwisieten roep ik de functie rechtstreeks aan, dit zou een oneindige lusuitvoering hebben en zou je die fout geven, verwijder de functieaanroep alles werkt normaal.

render(){
    return(
      <div>
        <h3>Simple Counter</h3>
        <Counter
          value={this.props.counter}
          onIncrement={this.props.increment} <------ function call removed
          onDecrement={this.props.decrement} <-----------
          onIncrementAsync={this.props.incrementAsync} />
      </div>
    )
  }

Antwoord 3, autoriteit 3%

Dat gebeurt meestal als je belt

onClick={this.handleButton()}– let op de ()in plaats van:

onClick={this.handleButton}– merk op dat we de functie niet aanroepen wanneer we deze initialiseren


Antwoord 4, autoriteit 2%

HET PROBLEEMis hier: onClick={this.handleButtonChange(false)}

Wanneer u this.handleButtonChange(false)doorgeeft aan onClick, roept u in feite de functie aan met value = falseen stelt u onClick in op de geretourneerde waarde van de functie, die ongedefinieerd. Ook roept het aanroepen van this.handleButtonChange(false)vervolgens this.setState()aan, wat een re-render activeert, wat resulteert in een oneindige renderlus.

DE OPLOSSINGis om de functie in een lambda door te geven: onClick={() => this.handleButtonChange(false)}. Hier stelt u onClick in om gelijk te zijn aan een functie die handleButtonChange(false) aanroept wanneer op de knop wordt geklikt.

Het onderstaande voorbeeld kan helpen:

function handleButtonChange(value){
  console.log("State updated!")
}
console.log(handleButtonChange(false))
//output: State updated!
//output: undefined
console.log(() => handleButtonChange(false))
//output: ()=>{handleButtonChange(false);}

Antwoord 5

Als je argumenten probeert toe te voegen aan een handler in recompose, zorg er dan voor dat je je argumenten correct definieert in de handler. Het is in wezen een curried-functie, dus u wilt er zeker van zijn dat u het juiste aantal argumenten nodig heeft. Deze pagina heeft een goed voorbeeld van het gebruik van argumenten met handlers.

Voorbeeld (van de link):

withHandlers({
  handleClick: props => (value1, value2) => event => {
    console.log(event)
    alert(value1 + ' was clicked!')
    props.doSomething(value2)
  },
})

voor uw kind HOC en in de ouder

class MyComponent extends Component {
  static propTypes = {
    handleClick: PropTypes.func, 
  }
  render () {
    const {handleClick} = this.props
    return (
      <div onClick={handleClick(value1, value2)} />
    )
  }
}

dit vermijdt het schrijven van een anonieme functie uit uw handler om het probleem op te lossen door niet genoeg parameternamen op uw handler op te geven.


Antwoord 6

Van react docs Argumenten doorgeven aan event-handlers

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

Antwoord 7

Dezelfde waarschuwing wordt uitgezonden bij alle statuswijzigingen die worden uitgevoerd in een render()-aanroep.

Een voorbeeld van een lastig te vinden zaak:
Bij het renderen van een GUI-component met meerdere selecties op basis van statusgegevens en als de status niets heeft om weer te geven, wordt een aanroep van resetOptions()beschouwd als statuswijziging voor die component.

De voor de hand liggende fix is ​​om te doen resetOptions()in componentDidUpdate()in plaats van render().

Other episodes