javascript – 用redux创建秒表

我一直在试图做一个反应和减速的秒表.弄清楚如何在redux中设计这样的东西,我一直很麻烦.

想到的第一件事就是采取了一项START_TIMER动作来设定初始补偿值.之后,我使用setInterval一次又一次地发出一个TICK动作,通过使用offset来计算已经过去了多少时间,将其添加到当前时间,然后更新偏移量.

这种方法似乎有效,但我不知道如何清除间隔来阻止它.此外,似乎这种设计很差,可能还有更好的办法.

这是一个完整的JSFiddle,具有START_TIMER功能工作.如果你现在只想看看我的reducer的样子,那就是:

const initialState = {
  isOn: false,time: 0
};

const timer = (state = initialState,action) => {
  switch (action.type) {
    case 'START_TIMER':
      return {
        ...state,isOn: true,offset: action.offset
      };

    case 'STOP_TIMER':
      return {
        ...state,isOn: false
      };

    case 'TICK':
      return {
        ...state,time: state.time + (action.time - state.offset),offset: action.time
      };

    default: 
      return state;
  }
}

我真的很感激任何帮助.

解决方法

我可能建议使用不同的方式:仅存储计算商店中经过的时间所需的状态,并且让组件设置自己的间隔,但他们经常希望更新显示.

这样可以将动作调度保持在最小限度 – 只会启动和停止(并重置)定时器的动作.请记住,每次调度一个动作时,都会返回一个新的状态对象,然后每个连接的组件都会重新呈现(即使它们使用优化来避免包装组件中的重新渲染过多).此外,许多动作调度可能使得难以调试应用程序状态更改,因为您必须处理所有TICK以及其他操作.

以下是一个例子:

// Action Creators

function startTimer(baseTime = 0) {
  return {
    type: "START_TIMER",baseTime: baseTime,Now: new Date().getTime()
  };
}

function stopTimer() {
  return {
    type: "STOP_TIMER",Now: new Date().getTime()
  };
}

function resetTimer() {
  return {
    type: "RESET_TIMER",Now: new Date().getTime()
  }
}


// Reducer / Store

const initialState = {
  startedAt: undefined,stoppedAt: undefined,baseTime: undefined
};

function reducer(state = initialState,action) {
  switch (action.type) {
    case "RESET_TIMER":
      return {
        ...state,baseTime: 0,startedAt: state.startedAt ? action.Now : undefined,stoppedAt: state.stoppedAt ? action.Now : undefined
      };
    case "START_TIMER":
      return {
        ...state,baseTime: action.baseTime,startedAt: action.Now,stoppedAt: undefined
      };
    case "STOP_TIMER":
      return {
        ...state,stoppedAt: action.Now
      }
    default:
      return state;
  }
}

const store = createStore(reducer);

请注意,操作创建者和缩减器仅处理原始值,并且不使用任何间隔或TICK操作类型.现在,一个组件可以轻松地订阅这些数据,并按照需要进行更新:

// Helper function that takes store state
// and returns the current elapsed time
function getelapsedtime(baseTime,startedAt,stoppedAt = new Date().getTime()) {
  if (!startedAt) {
    return 0;
  } else {
    return stoppedAt - startedAt + baseTime;
  }
}

class Timer extends React.Component {
  componentDidMount() {
    this.interval = setInterval(this.forceUpdate.bind(this),this.props.updateInterval || 33);
  }

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

  render() {
    const { baseTime,stoppedAt } = this.props;
    const elapsed = getelapsedtime(baseTime,stoppedAt);

    return (
      <div>
        <div>Time: {elapsed}</div>
        <div>
          <button onClick={() => this.props.startTimer(elapsed)}>Start</button>
          <button onClick={() => this.props.stopTimer()}>Stop</button>
          <button onClick={() => this.props.resetTimer()}>Reset</button>
        </div>
      </div>
    );
  }
}

function mapStatetoProps(state) {
  const { baseTime,stoppedAt } = state;
  return { baseTime,stoppedAt };
}

Timer = ReactRedux.connect(mapStatetoProps,{ startTimer,stopTimer,resetTimer })(Timer);

您甚至可以在不同更新频率的同一数据上显示多个定时器:

class Application extends React.Component {
  render() {
    return (
      <div>
        <Timer updateInterval={33} />
        <Timer updateInterval={1000} />
      </div>
    );
  }
}

您可以在这里看到一个working JSBinhttps://jsbin.com/dupeji/12/edit?js,output

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...