setTimeout у React Native


76

Я намагаюся завантажити заставку для програми iOS, вбудованої в React Native. Я намагаюся досягти цього за допомогою стану класу, а потім функції setTimeout наступним чином:

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',
          }}/>
      );
    }
  }
}

Сторінка завантаження працює секунду, і тоді я думаю, коли setTimeout намагається змінити стан на true, моя програма аварійно завершує роботу: 'undefined не є об'єктом (оцінює this.setState)'. Я займаюся цим вже пару годин, чи є ідеї щодо того, як це виправити?


Переконайтеся, що час вашого пристрою відповідає часу вашого комп’ютера! Це трапилося зі мною і взяв , до жаль , довгий час до debug stackoverflow.com/questions/51163349 / ...
Махді Bashirpour

Відповіді:


150

Класична помилка JavaScript.

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

Коли setTimeoutбіжить this.setState, thisвже немає CowtanApp, але window. Якщо ви визначите функцію з =>позначенням, es6 автоматично зв’яжеться this.

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

Крім того, ви можете використовувати a let that = this;у верхній частині вашого render, а потім переключити свої посилання на локальну змінну.

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

Якщо не працює, використовуйте bind.

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

2
Врятував мене, дякую! Я новачок у js, це може бути безглуздо, але чи є спосіб зробити це за допомогою "традиційної" функції () {}?
t-gao

15

Напишіть нову функцію для часу очікування. Будь ласка, спробуйте це.

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',
      }}/>
  );
}
}
}

гаразд, це працює - дякую! Ви могли б пояснити, чому він не працював у рендері?
Філ

Я думаю, ви взагалі не можете написати жодних інструкцій у методі візуалізації. Ви можете використовувати функцію componentWillMount або componentDidMount для інструкцій із запуску.
Phyo

6
Це не спрацювало через проблему масштабування. У вашому вихідному коді у вас був setTineout (function () {який, коли в цьому блоці це стосується чогось іншого, а не вашого компонента. Альтернативою відповіді тут було б просто змінити виклик setTimeout на "Ситакс ES2015 Fat Arrow", наприклад : setTimeout (() => this.setState ((...)
rmevans9

7

Змінити цей код:

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

до наступного:

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

7

На ReactNative .53 для мене працює наступне:

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

'setTimeout' - це функція бібліотеки ReactNative.
'this.timeoutCheck' - це моя змінна для зберігання об'єкта тайм-ауту.
'this.setTimePassed' - це моя функція для виклику під час очікування.


4

Ви можете прив’язати thisсвою функцію, додавши .bind(this)безпосередньо до кінця визначення функції. Ви б переписали свій блок коду як:

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

4
const getData = () => {
// some functionality
}

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

Проста функція Settimout спрацьовує через 6000 мілісонд


2

Якщо хтось цього хоче, ви також можете зробити таймер асинхронним і дочекатися його:

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

Використання:

// do something
await delay(500); // wait 0.5 seconds
// do something else


1

Виглядає проблема, коли час роботи телефону / емулятора відрізняється від часу сервера (де працює реактор-рідний пакувальник). У моєму випадку була різниця в 1 хвилину між часом роботи телефону та комп’ютера. Після їх синхронізації (нічого фантастичного не зробив, телефон був налаштований на ручний час, і я просто налаштував його використовувати мережу (передбачений час)), все працювало нормально. Ця проблема з github допомогла мені знайти проблему.


1

Ніколи не викликайте setStateвнутрішній renderметод

Ви ніколи не повинні дзвонити setStateвсередину renderметоду. Чому? виклик setStateврешті активує renderметод знову. Це означає, що ви викликаєте setState (згаданий у вашому renderблоці) у циклі, який ніколи не закінчується. Правильний спосіб зробити це, використовуючи componentDidMountхук у React, приблизно так:

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 Використовуйте потрійні оператори для більш чистого, коротшого та читабельного коду.


0

Як і вище, це може допомогти деяким людям.

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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.