当前位置:  开发笔记 > 编程语言 > 正文

使用redux创建秒表

如何解决《使用redux创建秒表》经验,为你挑选了3个好方法。

我一直在努力制作一个反应和减速秒表.我一直在努力弄清楚如何在redux中设计这样的东西.

首先想到的是有一个START_TIMER设置初始offset值的动作.在那之后,我用来反复setInterval触发一个TICK动作,通过使用偏移计算已经过了多少时间,将其添加到当前时间,然后更新offset.

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

这是一个完整的JSFiddle,它具有START_TIMER正常运行的功能.如果您只是想看看我的减速机现在的样子,这里是:

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;
  }
}

我真的很感激任何帮助.



1> Michelle Til..:

我可能会建议以不同的方式进行此操作:仅存储计算商店中已用时间所需的状态,并让组件设置自己间隔,但通常他们希望更新显示.

这可以将操作调度保持在最低限度 - 仅调度启动和停止(和重置)计时器的操作.请记住,每次调度操作都会返回一个新的状态对象,然后每个connected组件重新渲染(即使它们使用优化来避免在包装组件中重新渲染太多).此外,许多操作调度可能使调试应用程序状态更改变得困难,因为您必须TICK与其他操作一起处理所有s.

这是一个例子:

// 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, startedAt, stoppedAt } = this.props;
    const elapsed = getElapsedTime(baseTime, startedAt, stoppedAt);

    return (
      
Time: {elapsed}
); } } function mapStateToProps(state) { const { baseTime, startedAt, stoppedAt } = state; return { baseTime, startedAt, stoppedAt }; } Timer = ReactRedux.connect(mapStateToProps, { startTimer, stopTimer, resetTimer })(Timer);

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

class Application extends React.Component {
  render() {
    return (
      
); } }

你可以在这里看到一个有效的JSBin:https://jsbin.com/dupeji/12/edit?js,output



2> andykenward..:

如果您打算在更大的应用程序中使用它,那么我会使用requestAnimationFrame而不是setInterval性能问题.当您显示毫秒时,您会在移动设备上注意到这一点,而不是在桌面浏览器上.

更新了JSFiddle

https://jsfiddle.net/andykenward/9y1jjsuz



3> sdgluck..:

您希望使用clearInterval带有调用结果的函数setInterval(唯一标识符)并停止该间隔执行任何进一步的操作.

因此,而不是声明一个setInterval内部start(),而是将其传递给reducer,以便它可以将其ID存储在状态:

interval作为操作对象的成员传递给调度程序

start() {
  const interval = setInterval(() => {
    store.dispatch({
      type: 'TICK',
      time: Date.now()
    });
  });

  store.dispatch({
    type: 'START_TIMER',
    offset: Date.now(),
    interval
  });
}

intervalSTART_TIMER动作减速器中存储新状态

case 'START_TIMER':
  return {
    ...state,
    isOn: true,
    offset: action.offset,
    interval: action.interval
  };

______

按照渲染组件 interval

通过在interval作为组件的属性:

const render = () => {
  ReactDOM.render(
    ,
    document.getElementById('app')
  );
}

然后,我们可以检查out组件中的状态,以根据是否存在属性来呈现它interval:

render() {
  return (
    

Time: {this.format(this.props.time)}

); }

______

停止计时器

要停止计时器,我们清除使用的间隔,clearInterval然后initialState再次应用:

case 'STOP_TIMER':
  clearInterval(state.interval);
  return {
    ...initialState
  };

______

更新了JSFiddle

https://jsfiddle.net/8z16xwd2/2/

推荐阅读
惬听风吟jyy_802
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有