Какой лучший способ очистить таймер в React Native, когда он достигнет 0? - PullRequest
0 голосов
/ 07 мая 2018

У меня есть простое приложение для таймера, которое однажды может превратиться в приложение Pomodoro. Я изучаю методы жизненного цикла прямо сейчас.

Вот проблема. Я хотел бы убрать таймер с экрана, как только он достигнет 0. В конце концов, он будет немедленно заменен другим таймером, но я еще не достиг этой части. Я почти уверен, что проблема здесь:

componentDidUpdate = () => {
  if (this.state.count-1 === -2) {
    this.props.timerOverCallback()
  }
}

Первоначально я пробовал это утверждение if: ! (This.state.count-1) . Счетчик продолжал очищаться в 2 вместо 0.

Затем я попытался this.state.count-1 === -1 , потому что это, казалось, имело смысл. Счетчик продолжал очищаться на 1 вместо 0.

К тому времени появился шаблон, и я попытался this.state.count-1 === -2 . У меня вопрос: зачем мне сравнивать с -2 вместо -1? Сравнение с -2 не кажется особенно надежным, правда. Так как же лучше всего очистить таймер на 0?

Вот полный код:

class Timer extends Component {

  static propTypes = {
    timerOverCallback: PropTypes.func.isRequired,
    count: PropTypes.number.isRequired,
  }

  constructor(props) {
    super(props)
    this.state = {
      timerOverCallback: this.props.timerOverCallback,
      count: this.props.count,
    }
  }

  decrease = () => {
    this.setState(
        prevState => ({count: prevState.count - 1})
    )
  }

  componentDidMount = () => {
    this.interval = setInterval(this.decrease, 1000)
  }

  componentDidUpdate = () => {
    if (this.state.count-1 === -2) {
      this.props.timerOverCallback()
    }
  }

  componentWillUnmount = () => { clearInterval(this.interval) }

  render() {
    return (
      <Text style={styles.count}>{this.state.count}</Text>
    )
  }
}

export default class App extends Component {
  constructor() {
    super()
    this.state = {
      timerOn: false,
    }
  }

  toggleTimer = () => {
    this.setState(
      prevState => ({timerOn: !prevState.timerOn})
    )
  }

  render() {
    return (
      <View
        style={styles.fillAndCenter}>
        {this.state.timerOn ?
          <Timer
            count={5}
            timerOverCallback={this.toggleTimer}
          /> : <View/>
        }
        <Button
          title='Toggle Timer'
          onPress={this.toggleTimer}
        />
        <Text>
          {this.state.timerOn ? 'On' : 'Off'}
        </Text>
      </View>
    )
  }
}

ОБНОВЛЕНИЕ 05/08/2018:

Я воспользовался советом Габака и разместил ...

if (this.state.count < 0) this.state.timerOverCallback()

... в этом. Уменьшаем и избавляемся от componentDidMount. Однако я понял, что компонент фактически достиг стадии визуализации своего жизненного цикла, когда this.state.count = -1, что кажется проблематичным. Это правда, что экран никогда не обновлялся до -1, но функция рендеринга определенно вызывалась, поэтому тот факт, что экран не обновлялся, казался случайным (верно!?).

И тогда я понял, что, даже если я был слишком разборчив, есть и простой способ исправить это:

shouldComponentUpdate = (nextProps, nextState) => {
  return nextState.count > -1
}

1 Ответ

0 голосов
/ 07 мая 2018

Это componentDidUpdate с сайта React-Native:

componentDidUpdate() is invoked immediately after updating occur

Допустим, на вашем экране отображается 0 (this.state.count = 0). this.decrease получает вызов => this.state.count = -1 => Компонент получает обновление => componentDidUpdate вызывается (до рендеринга, поэтому экран все еще показывает 0)

и this.state.count - 1 = -2, вы звоните timeOverCallback() и останавливаете экран от рендеринга текущего this.state.count, который -1

Вы можете изменить на this.state.count === -1 или, я думаю, лучше прекратить использовать componentDidUpdate, поставить чек на this.decrease: когда вы видите this.state.count < 0 звонки timeOverCallback()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...