ReactJS: setTimeout () не працює?


100

Маючи на увазі цей код:

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')
);

Хіба стан не повинен змінитися лише через 3 секунди? Це змінюється негайно.

Моя головна мета тут - змінювати стан кожні 3 секунди (з setInterval()), але оскільки він не працював, я спробував setTimeout(), що теж не працює. Було якесь світло на цьому? Дякую!


2
Якщо у вас є , foo(bar())то barбуде виконаний перший і її значення, що повертається передається foo.
Фелікс Клінг

@FelixKling, що здається правильним, але недоречним. Оскільки foo()тут саме для виконання barпісля бажаного тайм-ауту. Або я абсолютно помиляюся, і він виконується відразу, і повертає значення лише через потрібний час?
jbarradas

3
"Оскільки foo () тут саме для того, щоб виконати панель після бажаного часу очікування." Правильно, ось чому ви повинні передавати bar, а не викликати його та передавати його повертається значення. Чи очікували ви, що поведінка людини foo(bar())зміниться залежно від того, що fooробиться? Це було б справді дивно.
Фелікс Клінг

Відповіді:


241

Зробіть

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

В іншому випадку ви передаєте результат setStateдо setTimeout.

Ви також можете використовувати функції стрілок ES6, щоб уникнути використання thisключового слова:

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

1
Так, це має сенс, і це працює. Але хіба функція () не є функцією? То навіщо нам це пов’язувати? Я вже пробував, і це справді потрібно, я просто хотів знати, чому.
Вдячний

Я не розумію, чому ви говорите, що це передало б результат setTimeout, як це не змушує це працювати? Яка поведінка в такому випадку?
PositiveGuy

16
для тих з вас, хто вважає за краще використовувати функції стрілок ES6: setTimeout(() => {this.setState({ position: 1 })}, 3000)@PositiveGuy не впевнений, що досліджував це самостійно з моменту публікації цього запитання, але на той випадок: оригінальний приклад Даніеля повинен .bind(this)обмежити thisконтекст setState- інакше , thisавтоматично буде посилатися на контекст, в якому він викликається (у цьому випадку анонім functionпередається setTimeout). ES6 стрілок функції, однак, лексична область видимості - вони обмежують thisдо контексту , в якому вони називаються.
Zac Collier

1
Не працює ... setTimeout (() => {if (! This.props.logoIsLoading &&! This.props.isLoading) {console.log ('Чи відбудеться це?'); This.setState ({.. .this.state, shouldUpdate: false, itemToUpdate: null, modalIsOpen: false, modalTitle: 'Додати нову організацію'});}}, 100); Це в контексті синтаксичного класу цукрового класу Організації розширює Component {console.log ніколи не отримує console.log ('Чи станемось ми?'); Все до нього та після цього реєструється.
juslintek

@juslintek визначити не працює. будь-ласка, задайте нове запитання, якщо це необхідно.
Daniel A. White

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

Вищевикладене також спрацює, оскільки функція стрілки ES6 не змінює контекст this.


3
Синтаксис ES6 повинен бути прийнятою відповіддю на найкращі практики в React. Обидва будуть працювати, але це більш елегантно і з ручками this.
mccambridge

24

Щоразу, коли ми створюємо час очікування, ми повинні очистити його на компонентіWillUnmount, якщо він ще не спрацював.

      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')
);

11

Я знаю, що це трохи давно, але важливо зауважити, що React рекомендує очистити інтервал, коли компонент демонтується: https://reactjs.org/docs/state-and-lifecycle.html

Тому я хотів би додати цю відповідь до цієї дискусії:

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

8

setStateвикликається негайно через дужки! Оберніть його анонімною функцією, а потім викликайте:

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

6

Ви не сказали, хто зателефонував setTimeout

Ось як ви викликаєте час очікування без виклику додаткових функцій.

1. Ви можете зробити це, не роблячи додаткових функцій.

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

Використовує функцію.prototype.bind ()

setTimeout визначає місце розташування функції та зберігає його в контексті.

2. Ще один спосіб зробити те саме, навіть написавши ще менше коду.

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

Можливо, в якийсь момент використовується той самий метод прив'язки

SetTimeout бере лише місце розташування функції, а функція вже має контекст? У всякому разі, це працює!

ПРИМІТКА. Вони працюють з будь-якою функцією, яку ви використовуєте в js.


5

Ваша область коду ( this) буде вашим windowоб'єктом, а не вашим компонентом реагування, і саме тому він setTimeout(this.setState({position: 1}), 3000)буде аварійним чином.

Це походить від javascript, а не React, це закриття js


Отже, щоб прив’язати поточну область реагування компонента, зробіть так:

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

Або якщо ваш браузер підтримує es6 або ваш projs підтримує компіляцію es6 до es5, спробуйте також функцію стрілки, оскільки стрілка func має вирішити цю проблему:

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

3

Існує 3 способи отримати доступ до області всередині функції 'setTimeout'

Перший,

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

По-друге, використовувати функцію стрілки ES6, оскільки функція стрілки не має самої сфери дії (це)

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

Третій - прив’язати область дії всередині функції

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

1

Ви зробили помилку декларування синтаксису, використовуйте належне оголошення setTimeout

message:() => { 
  setTimeout(() => {this.setState({opened:false})},3000); 
  return 'Thanks for your time, have a nice day 😊! 
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.