ReactJS: setTimeout () funktioniert nicht?

101

Unter Berücksichtigung dieses Codes:

var Component = React.createClass({

    getInitialState: function () {
        return {position: 0};    
    },

    componentDidMount: function () {
        setTimeout(this.setState({position: 1}), 3000);
    },

    render: function () {
         return (
            <div className="component">
                {this.state.position}
            </div>
         ); 
    }

});

ReactDOM.render(
    <Component />,
    document.getElementById('main')
);

Soll sich der Zustand nicht erst nach 3 Sekunden ändern? Es ändert sich sofort.

Mein Hauptziel hier ist es, den Status alle 3 Sekunden (mit setInterval()) zu ändern , aber da es nicht funktioniert hat, habe ich es versucht setTimeout(), was auch nicht funktioniert. Irgendwelche Lichter dazu? Vielen Dank!

jbarradas
quelle
2
Wenn Sie foo(bar())dann haben, barwird zuerst ausgeführt und sein Rückgabewert wird an übergeben foo.
Felix Kling
@FelixKling das scheint richtig, aber nicht angemessen. Da ist das foo()hier genau barnach gewünschtem Timeout auszuführen . Oder irre ich mich völlig und es wird sofort ausgeführt und gibt den Wert erst nach der gewünschten Zeit zurück?
Jbarradas
3
"Da das foo () hier genau ist, um den Balken nach dem gewünschten Timeout auszuführen." Richtig, deshalb müssen Sie es übergeben bar, nicht aufrufen und seinen Rückgabewert übergeben. Haben Sie erwartet, dass sich das Verhalten foo(bar())ändert, je nachdem, was foogerade getan wird? Das wäre wirklich seltsam.
Felix Kling

Antworten:

241

Machen

setTimeout(
    function() {
        this.setState({ position: 1 });
    }
    .bind(this),
    3000
);

Andernfalls übergeben Sie das Ergebnis von setStatean setTimeout.

Sie können auch Pfeilfunktionen verwenden, um die Verwendung des Schlüsselworts 'this' zu vermeiden: Do.

setTimeout(
    function() {
        this.setState({ position: 1 });
    }
    .bind(this),
    3000
);

Andernfalls übergeben Sie das Ergebnis von setStatean setTimeout.

Sie können auch ES6-Pfeilfunktionen verwenden, um die Verwendung von thisSchlüsselwörtern zu vermeiden :

setTimeout(
  () => this.setState({ position: 1 }), 
  3000
);
Daniel A. White
quelle
1
Ja macht Sinn und es funktioniert. Aber ist function () keine Funktion? Warum sollten wir es also binden müssen? Ich habe es bereits versucht und es wird wirklich gebraucht, ich wollte nur wissen warum.
Schätzen Sie
Ich verstehe nicht, warum Sie sagen, dass das Ergebnis an setTimeout übergeben wird. Wie funktioniert das nicht? Wie ist das Verhalten in diesem Fall?
PositiveGuy
16
Für diejenigen unter Ihnen, die ES6- setTimeout(() => {this.setState({ position: 1 })}, 3000)Pfeilfunktionen bevorzugen: @PositiveGuy Sie sind sich nicht sicher, ob Sie dies selbst recherchiert haben, seit diese Frage gestellt wurde, aber falls Sie dies nicht getan haben: Daniels ursprüngliches Beispiel muss .bind(this)den thisKontext auf setState- ansonsten beschränken , thisverweist automatisch auf den Kontext, in dem es aufgerufen wird (in diesem Fall wird der anonyme Kontext functionübergeben setTimeout). ES6- Pfeilfunktionen sind jedoch lexikalisch begrenzt - sie beschränken sich thisauf den Kontext, in dem sie aufgerufen werden.
Zac Collier
1
Funktioniert nicht ... setTimeout (() => {if (! This.props.logoIsLoading &&! This.props.isLoading) {console.log ('Werden wir passieren?'); This.setState ({.. .this.state, shouldUpdate: false, itemToUpdate: null, modalIsOpen: false, modalTitle: 'Neue Organisation hinzufügen'});}}, 100); Seine im Kontext der Klasse syntaktische Zuckerklasse Organisationen erweitert Component {console.log bekommt nie console.log ('Werden wir passieren?'); Alles davor und danach wird protokolliert.
Juslintek
@juslintek definieren nicht funktionieren. Bitte stellen Sie bei Bedarf eine neue Frage.
Daniel A. White
150
setTimeout(() => {
  this.setState({ position: 1 });
}, 3000);

Dies würde auch funktionieren, da die ES6-Pfeilfunktion den Kontext von nicht ändert this.

Steven Scaffidi
quelle
3
Die ES6-Syntax sollte die akzeptierte Antwort für Best Practices in React sein. Beide werden funktionieren, aber dies ist eleganter und Griffe this.
McCambridge
24

Jedes Mal, wenn wir ein Timeout erstellen, sollten wir es auf componentWillUnmount löschen, falls es noch nicht ausgelöst wurde.

      let myVar;
         const Component = React.createClass({

            getInitialState: function () {
                return {position: 0};    
            },

            componentDidMount: function () {
                 myVar = setTimeout(()=> this.setState({position: 1}), 3000)
            },

            componentWillUnmount: () => {
              clearTimeout(myVar);
             };
            render: function () {
                 return (
                    <div className="component">
                        {this.state.position}
                    </div>
                 ); 
            }

        });

ReactDOM.render(
    <Component />,
    document.getElementById('main')
);
Khalid Azam
quelle
11

Ich weiß, dass dies etwas alt ist, aber es ist wichtig zu beachten, dass React empfiehlt, das Intervall zu löschen, in dem die Komponente nicht bereitgestellt wird: https://reactjs.org/docs/state-and-lifecycle.html

Deshalb möchte ich diese Antwort zu dieser Diskussion hinzufügen:

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
Fernando Lopes
quelle
8

setStatewird aufgrund der Klammer sofort aufgerufen! Wickeln Sie es in eine anonyme Funktion ein und rufen Sie es dann auf:

setTimeout(function() {
    this.setState({position: 1})
}.bind(this), 3000);
tymeJV
quelle
6

Sie haben nicht gesagt, wer setTimeout aufgerufen hat

Hier erfahren Sie, wie Sie Timeout aufrufen, ohne zusätzliche Funktionen aufzurufen.

1. Sie können dies tun, ohne zusätzliche Funktionen auszuführen.

setTimeout(this.setState.bind(this, {position:1}), 3000);

Verwendet function.prototype.bind ()

setTimeout nimmt den Speicherort der Funktion und hält sie im Kontext.

2. Eine andere Möglichkeit, dasselbe zu tun, indem Sie noch weniger Code schreiben.

setTimeout(this.setState, 3000, {position:1});

Verwendet wahrscheinlich irgendwann die gleiche Bindemethode

Das setTimeout nimmt nur den Speicherort der Funktion ein und die Funktion hat bereits den Kontext? Wie auch immer, es funktioniert!

HINWEIS: Diese funktionieren mit allen Funktionen, die Sie in js verwenden.

Advis
quelle
5

Ihr Code scope ( this) wird Ihr windowObjekt sein, nicht Ihre Reaktionskomponente, und deshalb setTimeout(this.setState({position: 1}), 3000)stürzt er auf diese Weise ab.

Das kommt von Javascript nicht React, es ist js Closure


Gehen Sie folgendermaßen vor, um Ihren aktuellen Reaktionskomponentenbereich zu binden:

setTimeout(function(){this.setState({position: 1})}.bind(this), 3000);

Oder wenn Ihr Browser es6 unterstützt oder Ihre Projekte das Kompilieren von es6 zu es5 unterstützen, versuchen Sie es auch mit der Pfeilfunktion, da die Pfeilfunktion dieses Problem beheben soll:

setTimeout(()=>this.setState({position: 1}), 3000);
Xin
quelle
3

Es gibt drei Möglichkeiten, auf den Bereich innerhalb der Funktion 'setTimeout' zuzugreifen

Zuerst,

const self = this
setTimeout(function() {
  self.setState({position:1})
}, 3000)

Zweitens ist die Verwendung der ES6-Pfeilfunktion, da die Pfeilfunktion selbst keinen Gültigkeitsbereich hatte (dies)

setTimeout(()=> {
   this.setState({position:1})
}, 3000)

Der dritte besteht darin, den Bereich innerhalb der Funktion zu binden

setTimeout(function(){
   this.setState({position:1})
}.bind(this), 3000)
Darryl Fabian
quelle
1

Sie haben einen Syntaxdeklarationsfehler gemacht. Verwenden Sie die richtige setTimeout-Deklaration

message:() => { 
  setTimeout(() => {this.setState({opened:false})},3000); 
  return 'Thanks for your time, have a nice day 😊! 
}
KARTHIKEYAN.A
quelle