Что не так с моим таймером React Native здесь? - PullRequest
0 голосов
/ 10 апреля 2020

Мой код предназначен для запуска таймера на 20 минут -> 20:00. Мне кажется, что-то не хватает в коде. Мой setState не меняет значение time , когда я вызываю его в Timer ():

class Sleep extends Component {
  // create constructor to get access to props
  constructor(props) {
    super(props);
    this.state = {
      time: 1200,
      timer: '',
    };
  }

  componentDidMount() {
    this.interval = setInterval(this.Timer(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  Timer() {
    console.log('time is ' + this.state.time);

    this.setState({
      time: this.state.time - 1,
    });

    console.log('time is ' + this.state.time);
    var timer;

    var minutes = Math.floor(this.state.time / 60);
    var seconds = this.state.time % 60;

    if (minutes < 10) {
      minutes = '0' + minutes.toString();
    }

    if (seconds < 10) {
      seconds = '0' + seconds.toString();
    }

    timer = minutes.toString() + ':' + seconds.toString();

    this.setState({
      timer: timer,
    });
  }

  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: '#FFFFFF', paddingBottom: 100 }}>
        <View>
          <Text style={styles.timerText}>{this.state.timer}</Text>
        </View>
      </View>
    );
  }
}

Таймер должен просто отсчитывать время с 20:00 до 00:00 каждую секунду. Я добавил несколько операторов console.log (), чтобы попытаться диагностировать проблему.

1 Ответ

0 голосов
/ 10 апреля 2020

Timer определение функции не имеет this класса, связанного с ним, поэтому, когда оно вызывает this.setState, оно не совпадает this с компонентом. У вас есть 2 варианта.

Опция 1: привязать this к Timer в конструкторе

constructor(props) {
  super(props);
  this.state = {
    time: 1200,
    timer: '',
  };
  this.Timer = this.Timer.bind(this);
}

Опция 2: использовать функцию стрелки ES6 для автоматического связывания этого с вызывающим абонентом

Timer = () => {...};

Примечание: имена функций, как правило, должны быть в camelCased, а не в PascalCased

Вы можете немного упростить логику вашего компонента c. Во-первых, отображаемое время может быть получено из числового значения состояния time, поэтому нет необходимости хранить и то и другое. Во-вторых, похоже, что вы пытаетесь обновить время , а затем использовать это новое время для вычисления отображаемого времени. Обновления состояния реакции являются асинхронными, поэтому следующее значение состояния не будет доступно до следующего цикла рендеринга.

Просто обновите состояние в обратном вызове setInterval и вычислите полученное время отображения в функции рендеринга.

Sleep.jsx

class Sleep extends Component {
  state = {
    time: 60 * 20 // 20 minutes
  };

  componentDidMount() {
    this.interval = setInterval(
      // functional state update to ensure state is correctly updated
      // from previous state
      () => this.setState(({ time }) => ({ time: time - 1 })),
      1000
    );
  }

  componentDidUpdate() {
    const { time } = this.state;
    if (time <= 0) {
      clearInterval(this.interval);
    }
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    const { time } = this.state;
    const minutes = String(Math.floor(time / 60)).padStart(2, "0");
    const seconds = String(time % 60).padStart(2, "0");

    return (
      <div>
        {minutes}:{seconds}
      </div>
    );
  }
}

Edit countdown clock

...