【问题标题】:One-time working timer一次性工作计时器
【发布时间】:2017-02-23 07:53:30
【问题描述】:

我感到自己完全糊涂了,因为我从昨天开始仍在处理这个问题,没有任何帮助。 所以,问题:我有待办事项列表。每个任务都有计时器。只有一个计时器可以同时工作,因此用户只能同时执行一项任务。 我认为我可以在禁用另一个任务时执行“开始”按钮,当其中一个计时器运行时,但我认为我在 setState 中犯了错误,因为所有计时器仍在一起运行 =( 我阅读了文档,但这对我没有帮助。 另外,我有生成这些任务的文件 TodoTextInput,我想也许我应该在这里粘贴我的计时器,但这很奇怪。

关于完整信息,我在这里留下两个文件。 感谢您的帮助!

TodoItem (在这里发布)

import React, { Component, PropTypes } from 'react'
import classnames from 'classnames'
import TodoTextInput from './TodoTextInput'

export default class TodoItem extends Component {
    constructor(props) {
    super(props);
    this.state = { secondsStart: this.props.minSeconds, timerRunning: false }
  }

    static propTypes = {
    todo: PropTypes.object.isRequired,
    deleteTodo: PropTypes.func.isRequired,
    completeTodo: PropTypes.func.isRequired,
  }

  static defaultProps = {
      minSeconds: 0
  }
  handleSave = (id, text) => {
    if (text.length === 0) {
      this.props.deleteTodo(id)
    }
  }

handleStartClick = () => {
    if (!this.state.timerRunning) {
      this.incrementer = setInterval(() => {
        this.setState({
          secondsStart: (this.state.secondsStart + 1)
        });
      }, 1000)
      this.setState({
        timerRunning: true,
        currentTodoId: this.props.todo.id,
        runningTodoId: this.props.todo.id
      });
    }
  }


  getSeconds = () => {
    return ('0' + this.state.secondsStart % 60).slice(-2)
  }

   getMinutes = () => {
    return Math.floor((this.state.secondsStart / 60)%60)
  }
    getHoures = () => {
    return Math.floor((this.state.secondsStart / 3600)%24)
  }


  handleStopClick = () => {
    clearInterval(this.incrementer)
    this.setState({ timerRunning: false, currentTodoId: null, runningTodoId: null });
  }

  render() {
  const { todo, completeTodo, deleteTodo} = this.props

  const element = this.state.todo ? (
      <TodoTextInput text={todo.text}
        onSave={(text) => this.handleSave(todo.id, text)} />
    ) : (
        <div className="view">
          <input className="toggle"
            type="checkbox"
            checked={todo.completed}
            onChange={() => completeTodo(todo.isRequired)} />
          <label>
            {todo.text}
          </label>
          <div className="buttons">
            <h6>{this.getHoures()}:{this.getMinutes()}:{this.getSeconds()}</h6>
            {(this.state.secondsStart === 0)
              ? <button className="timer-start" onClick={this.handleStartClick} disabled={this.state.timerRunning }>Start</button>
              : <button className="timer-stop" onClick={this.handleStopClick} disabled={!this.state.timerRunning && this.state.runningTodoId !== this.state.currentTodoId}>Stop</button>
            }
          </div>
          <button className="destroy"
            onClick={() => deleteTodo(todo.id)} />
        </div>
      )

    return (
      <li className={classnames({
        completed: todo.completed,
      })}>
        {element}
      </li>
    )
  }
}

TodoTextInput (以防万一)

import React, { Component, PropTypes } from 'react'
import classnames from 'classnames'

export default class TodoTextInput extends Component {
  static propTypes = {
    onSave: PropTypes.func.isRequired,
    text: PropTypes.string,
    placeholder: PropTypes.string,
    newTodo: PropTypes.bool
  }

  state = {
    text: this.props.text || ''
  }

  handleSubmit = e => {
    const text = e.target.value.trim()
    if (e.which === 13) {
      this.props.onSave(text)
      if (this.props.newTodo) {
        this.setState({ text: '' })
      }
    }
  }

  handleChange = e => {
    this.setState({ text: e.target.value })
  }

  handleBlur = e => {
    if (!this.props.newTodo) {
      this.props.onSave(e.target.value)
    }
  }

  render() {
    return (
      <input className={
        classnames({
          'new-todo': this.props.newTodo
        })}
        type="text"
        placeholder={this.props.placeholder}
        autoFocus="true"
        value={this.state.text}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        onKeyDown={this.handleSubmit} />
    )
  }
}

【问题讨论】:

  • 所以我知道问题是您希望在启动时禁用所有计时器,对吗?你在哪里使用 TodoItem 组件?
  • 是的,当我在一项任务中单击“开始”时 - 我应该没有机会在另一项任务中单击“开始”。只有当我在此任务上单击“停止”时,我才能运行另一个任务和计时器。我在组件 MainSection 中导入的 TodoItem 组件 - 它是应用程序的最大部分。

标签: javascript reactjs timer state


【解决方案1】:

有很多方法可以做到这一点。您可以将当前运行的计时器的 id 存储在 MainSection 的状态中,并使用 completeTodo 之类的回调函数将其从 TodoItem 更改。然后,您可以将MainSection 状态的此属性作为道具发送给每个TodoItem,并检查它是否正在运行:

    render() {
      const { todo, runningTodoId, startTodoTimer, completeTodo, deleteTodo} = this.props
      let disable = runningTodoId == todo.id;
    }

重点是您需要与MainSection 通信,TodoItem 正在运行,或者至少如果有TodoItem 正在运行。据我所知,您所存储的有关计时器状态的所有内容都是 TodoItem 的本地状态,因此其他 TodoItems 不知道他们是否应该能够启动。

TODO 列表是almost a classic example of the Redux usage。我不知道您是否可以将 Redux 引入您的应用程序,但在存储全局状态方面,它绝对是一个很棒的工具。

【讨论】:

  • 是的,我在我的应用程序中使用 Redux,我只是用我的特性重写了“经典示例”。所以无论如何我需要与 MainSection 沟通,我是对的?
  • 要么与 MainSection 通信,要么使用 Redux 的 store。例如,如果您使用 Redux 存储当前正在运行的 Item 的 id,则不必将其存储在 MainSection 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-26
  • 1970-01-01
  • 2023-03-24
  • 2019-01-12
  • 1970-01-01
  • 2019-03-02
  • 2021-09-27
相关资源
最近更新 更多