In the previous post I added and removed list items. In this post I will implement a ticking timer.
The React Native ecosystem promises a rich set of components that work seamlessly together, much like the Ruby world. My first timer implementation used react-timer-machine, a fully controllable and customizable timer component.
$ yarn add react-timer-machine
import TimerMachine from 'react-timer-machine'
Time duration math is implemented by combining moment.js and moment-duration-format.
import moment from "moment";
import momentDurationFormatSetup from "moment-duration-format";
momentDurationFormatSetup(moment);
The timer itself will start as soon as the isMeetingStarted
state is toggled.
<TimerMachine
timeStart={1000}
started={this.state.isMeetingStarted}
countdown={false}
interval={1000}
formatTimer={(time, ms) =>
moment.duration(ms, "milliseconds").format("h [hours], m [minutes], s [seconds]")
}
/>
It works, except when it doesn’t. Expo doesn’t support background tasks and so the timer pauses when the app is backgrounded. A simple workaround is to keep track of start and end time, but we might as well get rid of the timer altogether.
We can rely on setInterval
to call a method every second in the foreground and update the elapsed time by subtracting two timestamps. I find simulating a timer in this manner pretty neat, as it takes full advantage of React re-rendering components when state changes. It obviously wouldn’t be suitable for performing an action based on elapsed time since no events fire in the background.
this.setState({ elapsedTime: moment().diff(this.state.meetingStartedAt) })
You can see this code in 33-minutes-app@0f1df4. In the next post I will wire up this React Native client app to a Rails GraphQL API.