Почему таймер на останавливается?

183
04 октября 2018, 16:30

В компоненте хочу реализовать таймер, по истечении которого надо сделать запрос. Пошуршал по гугглу и стеку примеры таймеров, прикрутил свое. Получилось следующее:

export default class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            secondsRemaining: 0
        }
    }
    componentDidUpdate(prevProps, prevState) {
        let {secondsRemaining} = prevState;
        if (secondsRemaining === 0) {
            // REQUEST
        } else {
            this.interval = setInterval(this.tick, 1000);
        }
    }

    handleItemClick = () => {
        this.setState({
            activeItem: itemIndex,
            secondsRemaining : data.time && data.time
        });
    };
    tick = () => {
        this.setState({secondsRemaining: this.state.secondsRemaining - 1});
        if (this.state.secondsRemaining <= 0) {
            clearInterval(this.interval);
        }
    };
}

По клику на айтем меню задействуется хендлер handleItemClick, который сетит в стейт secondsRemaining в секундах(например 60 секунд). Далее срабатывает didUpdate и условие таково, что когда secondsRemaining будет равно нулю, то надо выполнить запрос, если нет, ты с интервалом в 1 секунду методом SetInterval мы отсчитываем время. Это работает,но не совсем так как надо. Он доходит до 0 и продолжает отнимать -1,-2,-3 и так о бесконечности. Какой-то косяк в моей логике,но я не пойму какой. Подскажите пожалуйста

Answer 1
componentDidUpdate(prevProps, prevState) {
    let {secondsRemaining} = prevState;
    if (secondsRemaining === 0) {
        // REQUEST
    } else {
        this.interval = setInterval(this.tick, 1000);
    }
}

Метод componentDidUpdate вызывается каждый раз, как у вас срабатывает апдейт компонента, даже когда вы уже запустили таймер, то есть после каждого вызова таймера, вызывается этот метод, где проверяется условие, которое снова срабатывает ( таймер обновляется, правда старый таймер никуда не исчезает )

Поэтому в итоге у вас куча таймеров в памяти = утечка памяти

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      secondsRemaining: 100
    };
  }
  componentDidUpdate(prevProps, prevState) {
    let { secondsRemaining } = prevState;
    if (secondsRemaining === 0) {
      // REQUEST
    } else if (!this.interval) { // только если еще нет таймера
      this.interval = setInterval(this.tick, 10);
    }
  }
  componentWillUnmount() {
    // обязательно при анмаунте удаляем таймер
    clearInterval(this.interval);
    this.interval = undefined;
  }
  handleItemClick = () => {
    this.setState({
      secondsRemaining: 100
    });
  };
  tick = () => {
    this.setState({ secondsRemaining: this.state.secondsRemaining - 1 });
    if (this.state.secondsRemaining <= 0) {
      clearInterval(this.interval);
      this.interval = undefined;
    }
  };
  render() {
    return (
      <div>
        <div>{this.state.secondsRemaining}</div>
        <button onClick={this.handleItemClick}>click</button>
      </div>
    );
  }
}
const rootElement = document.getElementById("root");
ReactDOM.render(<MyComponent />, rootElement);
READ ALSO
Как создать круглый эффект огня при наведении

Как создать круглый эффект огня при наведении

Наткнулся на сайте Хоббита на такой прелестный эффект, который я обычно встречал в играх

185
циклы с функциями

циклы с функциями

у меня есть две функции getDep() и getRate(), и проверка(цикл), где getRate() не должен превышать getDep(), в общем do срабатывает два раза при вводе большего...

179
Как передать бинарный файл Java Servlet -&gt; html (js)

Как передать бинарный файл Java Servlet -> html (js)

С сервлета на клиент необходимо отправить торрент-файлВ JS не силён

161
Проблема с innerHTML в JS:(

Проблема с innerHTML в JS:(

Мне нужно изменить обе строки в html, но с помощью innerHTML получается изменить лишь одну строку (ту, где единица написана)

141