Modeling a Screensaver with a Statechart, a real use case.

Screensaver over the app

Last year I developed a touchable desktop application for a client (a museum) using Electron, React and a little custom CMS with NodeJS. The client requested that the app should have a Screensaver. The first requirements were:

  • The Screensaver should be opened at first.
  • When the user touches the Screensaver it should disappear.
  • Once disappeared, and if the user doesn’t interact with the app in 90 seconds, it should appear again.

Easy right? so let’s do it with a timeout 😉. First, we are gonna use 3 seconds as the inactive time instead of 90, I don’t wanna wait 90 seconds to test it out, also I’m gonna call this time SCREENSAVER_DELAY_MS.

At this time, the code doesn’t look so good but it’s not that hard to read. But, after showing how it’ll work, the client asked me to add one more requirement.

While the Screensaver is shown I want it to appear 5 minutes and disappear for 1 minute, and then appear 5 minutes and disappear 1 minute … and so on until the user interacts with the app.

The reason for this was to show to the user that the app is interactive, so let’s modify the code to meet the new requirement. I gonna call the new constants `SCREENSAVER_ACTIVE_TIME_MS` for the time the Screensaver is shown and `SCREENSAVER_INACTIVE_TIME_MS` for the time the Screensaver is hidden. In the code below I changed the original times, but it works like expected.

As you can see above, the code becomes more complex and difficult to read.

Modeling it with a statechart

I finally modeled it using a statechart and implemented it using XState. I used delayed transitions and found it so useful for this case. See how the final statechart code looks:

The statechart has two main states:

  • active: the Screensaver is shown, and switches between visible and hidden state until the user interacts with the app. When the user interacts with the app, the next state is inactive.
  • inactive: the Screensaver is hidden, and there is a timer for making it appear again.

I use a self-transition in the inactive state to reset the timer each time the user interacts with the app.

Note that the active state has two sub-states (is a compound state), visible and hidden, which are used to meet the latest client requirements.

In the example, I reduced the delays to be able to test it faster. Here the working code:

And that’s it! I achieved a simpler and cleaner code by modeling the Screensaver with a Statechart 🚀.

Unit Testing

It is so easy to test a statechart 👌, see some unit tests for the Screensaver machine in the machine.test.js file.

Do you wanna know more about this topic and other interesting tech topics?

Follow me on Medium and Twitter:

This article is part of a series about statecharts:

Happy hacking! 🤖

Many thanks to Eric Rabbath and Erik Mogensen for giving me feedback on the article.




Senior Software Engineer at Tribe. I create tools to make people more productive.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Architect 8.3: custom file paths & much more

React Native Authentication in Depth Part 2 — Real World Auth Flow

45 Amazing Node.js Open Source for the Past Year (v.2019)

Promise handlers for cleaner async syntax

Your Cross-platorm app: React JS vs. React Native

Why To Use Angular JS For Your Front-end Development!

Basic Hooks in React

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Carlos Galarza

Carlos Galarza

Senior Software Engineer at Tribe. I create tools to make people more productive.

More from Medium

Countdown in Reactjs From Event’s Timezone and Date

Handling Stale Closures and Accessing Latest State in React’s UseEffect.

Talking about the useState hook

A quick guide for passing props using navigation and UseLocation hook in react-router-dom