setTimeout in React Native

75

Ich versuche, einen Begrüßungsbildschirm für eine in React Native integrierte iOS-App zu laden. Ich versuche dies durch Klassenzustände und dann eine setTimeout-Funktion wie folgt zu erreichen:

class CowtanApp extends Component {
  constructor(props){
    super(props);
    this.state = {
      timePassed: false
    };
  }

  render() {
    setTimeout(function(){this.setState({timePassed: true})}, 1000);
    if (!this.state.timePassed){
      return <LoadingPage/>;
    }else{
      return (
        <NavigatorIOS
          style = {styles.container}
          initialRoute = {{
            component: LoginPage,
            title: 'Sign In',
          }}/>
      );
    }
  }
}

Die Ladeseite funktioniert eine Sekunde lang, und wenn setTimeout versucht, den Status auf true zu ändern, stürzt mein Programm ab: 'undefined ist kein Objekt (Auswertung dieses.setState)'. Ich bin schon seit ein paar Stunden dabei und habe Ideen, wie ich das beheben kann?

Phil
quelle
Überprüfen Sie, ob die Zeit Ihres Geräts mit der Ihres Computers übereinstimmt! Dies passierte mir und es dauerte leider lange, bis debug stackoverflow.com/questions/51163349/…
Mahdi Bashirpour

Antworten:

148

Klassischer Javascript-Fehler.

setTimeout(function(){this.setState({timePassed: true})}, 1000)

Wenn setTimeoutläuft this.setState, thisist nicht mehr CowtanApp, aber window. Wenn Sie die Funktion mit der =>Notation definieren, wird es6 automatisch gebunden this.

setTimeout(() => {this.setState({timePassed: true})}, 1000)

Alternativ können Sie ein let that = this;oben in Ihrem verwenden renderund dann Ihre Referenzen ändern, um die lokale Variable zu verwenden.

render() {
  let that = this;
  setTimeout(function(){that.setState({timePassed: true})}, 1000);

Wenn es nicht funktioniert, verwenden Sie bind.

setTimeout(
  function() {
      this.setState({timePassed: true});
  }
  .bind(this),
  1000
);
oliversisson
quelle
2
Hat mich gerettet, danke! Ich bin neu bei js, das mag albern sein, aber gibt es eine Möglichkeit, dies mit der "traditionellen" Funktion () {} zu tun?
T-Gao
15

Schreiben Sie eine neue Funktion für die Einstellung. Bitte versuchen Sie dies.

class CowtanApp extends Component {
  constructor(props){
  super(props);
  this.state = {
  timePassed: false
  };
}

componentDidMount() {
  this.setTimeout( () => {
     this.setTimePassed();
  },1000);
}

setTimePassed() {
   this.setState({timePassed: true});
}


render() {

if (!this.state.timePassed){
  return <LoadingPage/>;
}else{
  return (
    <NavigatorIOS
      style = {styles.container}
      initialRoute = {{
        component: LoginPage,
        title: 'Sign In',
      }}/>
  );
}
}
}
Phyo
quelle
Okay, das funktioniert - danke! Könnten Sie möglicherweise erklären, warum es beim Rendern nicht funktioniert hat?
Phil
Ich denke, Sie können überhaupt keine Anweisungen in der Render-Methode schreiben. Sie können die Funktion componentWillMount oder componentDidMount für Startanweisungen verwenden.
Phyo
6
Es funktionierte aufgrund eines Scoping-Problems nicht. In Ihrem ursprünglichen Code hatten Sie setTineout (function () {, was sich in diesem Block auf etwas anderes als Ihre Komponente bezieht. Eine Alternative zur Antwort hier wäre gewesen, einfach Ihren setTimeout-Aufruf in "ES2015 Fat Arrow Sytax" wie zu ändern : setTimeout (() => this.setState ((...)
rmevans9
7

Ändern Sie diesen Code:

setTimeout(function(){this.setState({timePassed: true})}, 1000);

Zu dem Folgendem:

setTimeout(()=>{this.setState({timePassed: true})}, 1000); 
wandhi Zakari
quelle
6

Auf ReactNative .53 funktioniert Folgendes für mich:

 this.timeoutCheck = setTimeout(() => {
   this.setTimePassed();
   }, 400);

'setTimeout' ist die ReactNative-Bibliotheksfunktion.
'this.timeoutCheck' ist meine Variable, um das Timeout-Objekt zu halten.
'this.setTimePassed' ist meine Funktion, die ich beim Timeout aufrufe.

David M Lee
quelle
4

Sie können sich thisan Ihre Funktion binden , indem Sie .bind(this)direkt am Ende Ihrer Funktionsdefinition hinzufügen . Sie würden Ihren Codeblock wie folgt umschreiben:

setTimeout(function () {
  this.setState({ timePassed: true });
}.bind(this), 1000);
Scott Carpenter
quelle
4
const getData = () => {
// some functionality
}

const that = this;
   setTimeout(() => {
   // write your functions    
   that.getData()
},6000);

Einfache Settimout-Funktion wird nach 6000 Millisekunden ausgelöst

krishnazden
quelle
2

setTimeout(()=>{this.setState({loaded: true})}, 1000);Verwenden Sie dies einfach für eine Zeitüberschreitung.

Biplov Kumar
quelle
1

Es scheint ein Problem zu geben, wenn sich die Zeit des Telefons / Emulators von der des Servers unterscheidet (auf dem der reaktionsnative Packager ausgeführt wird). In meinem Fall gab es einen Unterschied von 1 Minute zwischen der Zeit des Telefons und des Computers. Nachdem ich sie synchronisiert hatte (nichts Besonderes, das Telefon wurde auf manuelle Zeit eingestellt und ich habe es einfach so eingestellt, dass es die vom Netzwerk (sim) bereitgestellte Zeit verwendet), funktionierte alles einwandfrei. Dieses Github-Problem hat mir geholfen, das Problem zu finden.

Alex Buicescu
quelle
1

Rufen Sie niemals die setStateInside- renderMethode auf

Sie sollten niemalssetState innerhalb der renderMethode aufrufen . Warum? Der Aufruf setStatelöst die renderMethode schließlich erneut aus. Das bedeutet, dass Sie setState (in Ihrem renderBlock erwähnt) in einer Schleife aufrufen , die niemals enden würde. Der richtige Weg, dies zu tun, ist die Verwendung von componentDidMountHook in React, wie folgt :

class CowtanApp extends Component {
  state = {
     timePassed: false
  }

  componentDidMount () {
     setTimeout(() => this.setState({timePassed: true}), 1000)
  }

  render () {
    return this.state.timePassed ? (
        <NavigatorIOS
          style = {styles.container}
          initialRoute = {{
            component: LoginPage,
            title: 'Sign In',
        }}/>
    ) : <LoadingPage/>
  }
}

PS Verwenden Sie ternäre Operatoren für saubereren, kürzeren und lesbaren Code.

UtkarshPramodGupta
quelle
1

Falls es jemand möchte, können Sie den Timer auch asynchronisieren und darauf warten:

export const delay = (ms) => new Promise((res) => setTimeout(res, ms));

Verwendung:

// do something
await delay(500); // wait 0.5 seconds
// do something else
Eric Wiener
quelle
0

Das gleiche wie oben, könnte einigen Menschen helfen.

setTimeout(() => {
  if (pushToken!=null && deviceId!=null) {
    console.log("pushToken & OS ");
    this.setState({ pushToken: pushToken});
    this.setState({ deviceId: deviceId });
    console.log("pushToken & OS "+pushToken+"\n"+deviceId);
  }
}, 1000);
Dunken_sai
quelle