JS thread seems to get paused

Viewed 397

I have a question. I am still a newbie at react-native but I can't find anything related to my question. Not in the react/react-native docs neither with google.

I already had this problem in my last project, but I never finished it and also didn't tried to solve it.

So the problem is:

If I use this.setState() or this.props.navigator.resetTo() from react-native-navigation, it just does nothing until I touch somewhere at my display or rotate my device. Also it is enough to focus and un-focus the ios simulator.

It seems like the JS thread gets paused until I input something. This also happens when I use an mobx observable. But with an observable, it happens not so often than with setState(). This is why I moved all of my local states to an local mobx store, it improved my situation, but still sometimes it happens that react-native somehow waits for an touch input. One thing I also tried is to wrap every resetTo() in an requestAnimationFrame(), also this improved my situation a little bit.

Now an example code:

This is my initial screen which opens the realm database.

import React, {Component} from 'react';
import {View, Dimensions} from 'react-native';
import Schema from '../Schema';
import {Everything, Untis, NavigateEverywhere} from '../Stores/index';
import {Text} from 'react-native-elements';
// import * as Progress from 'react-native-progress';
import percentage from 'percentage-calc';
import Realm from 'realm';
import {observable} from "mobx"
import {observer} from 'mobx-react';
import {MKProgress} from 'react-native-material-kit';

@observer
class Database extends Component {

 constructor(props) {
  super(props);
  console.ignoreWarnings = ['Realm.openAsync'];
  NavigateEverywhere.setNavigator(this.props.navigator);
 }


 // state = {
 //  statusText: 'Initializing Database...',
 //  uploadProgress: 0,
 //  downloadProgress: 0,
 //  uploadMax: 0,
 //  downloadMax: 0,
 //  uploadCurrent: 0,
 //  downloadCurrent: 0,
 //  workingUpload: false,
 //  workingDownload: false,
 //  realmHost: this.realmHost,
 //  realmServer: `http://${this.realmHost}/`,
 //  realm: `realm://${this.realmHost}/~/sitnu`
 // };

 @observable statusText = 'Initializing Database...';
 @observable uploadProgress = 0;
 @observable downloadProgress = 0;
 @observable uploadMax = 0;
 @observable downloadMax = 0;
 @observable uploadCurrent = 0;
 @observable downloadCurrent = 0;
 @observable workingUpload = false;
 @observable workingDownload = false;
 realmHost = '';
 realmServer = `http://${this.realmHost}/`;
 realm = `realm://${this.realmHost}/~/sitnu`;

 componentDidMount() {
  this.bootStrap().catch(console.error);
 }

 async bootStrap() {
  let user;
  if (this.props.token && this.props.provider) {
   try {
    user = await Realm.Sync.User.registerWithProvider(this.realmServer, {
     provider: this.props.provider,
     providerToken: this.props.token
    });
   } catch (e) {
    return this.props.navigator.resetTo({
     screen: 'io.LoginRealm',
     title: 'Login into Realm',
     passProps: {
      error: e
     }
    });
   }
  }
  if (this.props.username && this.props.password) {
   try {
    user = await new Promise((resolve, reject) => {
     Realm.Sync.User.login(this.realmServer, this.props.username, this.props.password, (err, u) => {
      if (err) return reject(err);
      resolve(u);
     });
    });
   } catch (e) {
    return this.props.navigator.resetTo({
     screen: 'io.LoginRealm',
     title: 'Login into Realm',
     passProps: {
      error: e
     }
    });
   }
  }

  let users = [];
  for (let key in Realm.Sync.User.all) {
   users.push(Realm.Sync.User.all[key]);
  }
  if (users.length !== 0 && !user) {
   user = users[0];
  }

  if (!user) {
   return this.props.navigator.resetTo({
    screen: 'io.LoginRealm',
    title: 'Login into Realm',
    passProps: {
     error: 'user is undefined or null'
    }
   });
  }
  let realm;
  try {
   realm = await new Promise((resolve, reject) => {
    Realm.openAsync({
     schema: Schema,
     sync: {
      user: user,
      url: this.realm
     }
    }, (error, realm) => {
     if (error) return reject(error);
     resolve(realm);
    }, this.downloadCallback.bind(this));
   });
  } catch (e) {
   console.log("Why");
   return requestAnimationFrame(() => {
    this.props.navigator.resetTo({
     screen: 'io.LoginRealm',
     title: 'Login into Realm',
     passProps: {
      error: e
     }
    });
   });
  }

  this.workingUpload = false;
  this.workingDownload = false;
  this.statusText = 'Finishing Database...';

  Everything.setRealm(realm);

  const username = realm.objectForPrimaryKey('KeyValue', 'username');
  const password = realm.objectForPrimaryKey('KeyValue', 'password');
  const host = realm.objectForPrimaryKey('KeyValue', 'host');
  const school = realm.objectForPrimaryKey('KeyValue', 'school');
  const setup = realm.objectForPrimaryKey('KeyValue', 'setup');
  if (typeof username === 'object' && typeof password === 'object' && typeof host === 'object' && typeof school === 'object' && typeof setup === 'object' && username.value && password.value && host.value && school.value && setup.value) {
   Everything.setCredentials(username.value, password.value, host.value, school.value);
   Untis.setSettings(username.value, password.value, host.value, school.value);
   requestAnimationFrame(() => {
    this.props.navigator.resetTo({
     screen: 'io.Home',
     animated: true,
     title: 'Home'
    });
   });
  } else {
   requestAnimationFrame(() => {
    this.props.navigator.resetTo({
     screen: 'io.Login',
     animated: true,
     navigatorStyle: {
      navBarHidden: true,
      statusBarTextColorSchemeSingleScreen: 'dark'
     }
    });
   });
  }
 }

 downloadCallback = async (transferred, transferable) => {
  this.workingDownload = true;
  this.downloadMax = transferable;
  this.downloadCurrent = transferred;
  this.downloadProgress = percentage.from(transferred, transferable) / 100;
  this.statusText = 'Sync Database';
 };

 render() {
  return (
   <View style={{
    alignContent: "center",
    alignItems: "center",
    alignSelf: "center",
    flex: 1,
    justifyContent: "center"
   }}>
    <Text h5>{this.statusText ? <Text>{this.statusText}</Text> : null}</Text>
    {this.workingUpload ? <View>
     {/*<Progress.Bar progress={this.uploadProgress}/>*/}
     <MKProgress style={{width: Dimensions.get('window').width - 40}} progress={this.uploadProgress}/>
     <Text>Upload {this.uploadCurrent ?
      <Text>{this.uploadCurrent}</Text> : null}/{this.uploadMax ?
      <Text>{this.uploadMax}</Text> : null}</Text>
    </View> : null}
    {this.workingDownload ? <View style={{
     alignContent: 'center',
     alignItems: 'center',
     alignSelf: 'center',
     justifyContent: 'center'
    }}>
     {/*<Progress.Bar progress={this.downloadProgress}/>*/}
     <MKProgress style={{width: Dimensions.get('window').width - 40}} progress={this.downloadProgress}/>
     <Text>Download {this.downloadCurrent ?
      <Text>{this.downloadCurrent}</Text> : null}/{this.downloadMax ?
      <Text>{this.downloadMax}</Text> : null}</Text>
    </View> : null}
   </View>
  );
 }

}

export default Database;

Maybe it is just something completely stupid and I just don't see it, but I already tried many things and don't know what to do.

Greetings Nils

2 Answers

I had a similar issue once. This issue came from the react-native debug bridge. Try to disable the debug mode. Or if it's not working, try to generate & install a release version.

Right click on browser and open inspect Element mode. Then select debugger menu. There you will find a option "pause script execution on error". Enable this option. If any thread stops or there is any error, script execution will be stopped and you can see the error on console. Let me know if still you face problem.

Related