web-dev-qa-db-de.com

ReactJS: Warnung: setState (...): Aktualisierung während eines vorhandenen Statusübergangs nicht möglich

Ich versuche, den folgenden Code aus meiner Renderansicht umzuändern:

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

auf eine Version, bei der sich die Bindung innerhalb des Konstruktors befindet. Der Grund dafür ist, dass bind in der Render-Ansicht zu Leistungsproblemen führt, insbesondere bei Mobiltelefonen der unteren Preisklasse. 

Ich habe den folgenden Code erstellt, erhalte jedoch ständig die folgenden Fehler (viele). Es sieht so aus, als würde die App in eine Schleife geraten:

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`.

Unten ist der Code, den ich verwende:

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;
141
user3611459

Sieht aus, als würden Sie versehentlich die handleButtonChange-Methode in Ihrer Render-Methode aufrufen, möchten Sie wahrscheinlich stattdessen onClick={() => this.handleButtonChange(false)}.

Wenn Sie im onClick-Handler kein Lambda erstellen möchten, müssen Sie über zwei gebundene Methoden verfügen, eine für jeden Parameter.

In der constructor:

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

Und in der render-Methode:

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

Aus den Antwortdokumenten Argumente an Event-Handler übergeben

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

Wenn Sie versuchen, einem Handler in recompose Argumente hinzuzufügen, stellen Sie sicher, dass Sie Ihre Argumente im Handler richtig definieren. Es handelt sich im Wesentlichen um eine Curry-Funktion, daher möchten Sie sicher sein, dass Sie die richtige Anzahl von Argumenten benötigen. Diese Seite bietet ein gutes Beispiel für die Verwendung von Argumenten mit Handlern.

Beispiel (aus dem Link):

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

für Ihr Kind HOC und im Elternteil

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

dadurch wird vermieden, dass eine anonyme Funktion aus Ihrem Handler geschrieben wird, um das Problem zu beheben, dass nicht genügend Parameternamen für Ihren Handler angegeben werden.

2
Nick Brady

Ich gebe ein allgemeines Beispiel zum besseren Verständnis, im folgenden 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>
    )
  }

Beim Bereitstellen von Requisiten rufe ich die Funktion direkt auf. Diese Ausführung hat eine Endlosschleifenausführung und würde Ihnen diesen Fehler anzeigen. Remove the function call alles funktioniert normal. 

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>
    )
  }
1
Ignatius Andrew

Ich habe den gleichen Fehler erhalten, als ich anrief 

this.handleClick = this.handleClick.bind(this);

in meinem Konstruktor, wenn handleClick nicht existierte  

(Ich hatte es gelöscht und hatte versehentlich die verbindliche Aussage "this" in meinem Konstruktor gelassen).

Lösung = Entfernen Sie die Bindungsaussage "this".

1
Sam Henderson

Das Problem ist sicherlich das diese Bindung beim rendern des Buttons mit dem onClick-Handler. Die Lösung besteht darin, die Pfeilfunktion zu verwenden, während der Aktionshandler beim Rendern aufgerufen wird. Wie folgt: onClick={ () => this.handleButtonChange(false) }

1
FEUYAN TCHOUO

Die Lösung, die ich zum Öffnen von Popover für Komponenten verwende, ist -reactstrap (React Bootstrap 4 components) .

    class Settings extends Component {
        constructor(props) {
            super(props);

            this.state = {
              popoversOpen: [] // array open popovers
            }
        }

        // toggle my popovers
        togglePopoverHelp = (selected) => (e) => {
            const index = this.state.popoversOpen.indexOf(selected);
            if (index < 0) {
              this.state.popoversOpen.Push(selected);
            } else {
              this.state.popoversOpen.splice(index, 1);
            }
            this.setState({ popoversOpen: [...this.state.popoversOpen] });
        }

        render() {
            <div id="settings">
                <button id="PopoverTimer" onClick={this.togglePopoverHelp(1)} className="btn btn-outline-danger" type="button">?</button>
                <Popover placement="left" isOpen={this.state.popoversOpen.includes(1)} target="PopoverTimer" toggle={this.togglePopoverHelp(1)}>
                  <PopoverHeader>Header popover</PopoverHeader>
                  <PopoverBody>Description popover</PopoverBody>
                </Popover>

                <button id="popoverRefresh" onClick={this.togglePopoverHelp(2)} className="btn btn-outline-danger" type="button">?</button>
                <Popover placement="left" isOpen={this.state.popoversOpen.includes(2)} target="popoverRefresh" toggle={this.togglePopoverHelp(2)}>
                  <PopoverHeader>Header popover 2</PopoverHeader>
                  <PopoverBody>Description popover2</PopoverBody>
                </Popover>
            </div>
        }
    }
0
dev-siberia

Die gleiche Warnung wird bei jeder Statusänderung ausgegeben, die in einem Aufruf von render() ausgeführt wird.

Ein Beispiel für einen schwierig zu findenden Fall: .__ Wenn beim Rendern einer Multi-Select-GUI-Komponente basierend auf Statusdaten nichts angezeigt wird, wird ein Aufruf von resetOptions() als Statusänderung für diese Komponente betrachtet.

Die naheliegende Lösung besteht darin, resetOptions() in componentDidUpdate() anstelle von render() auszuführen.

0
Jari Turkia