loading...
Cover image for Bugfix: Spelunking in Someone Else's Code

Bugfix: Spelunking in Someone Else's Code

tiffany profile image Tiffany White ・4 min read

This article was first published on my blog.

I love CodeSandbox. It has pretty much replaced CodePen for me unless I am fiddling around with CSS or freeCodeCamp front-end projects.

I like going through the sandboxes and picking out different ones to look at, take apart, and figure out how they work.

While going through React Tutorial for Beginners by Kent C. Dodds on Egghead.io I decided I would look for sandboxes that correlate with the course as I was using Codesandbox to build out the stopwatch we were building in that course.

I found a sandbox which I forked and found it to be buggy.

Why didn't the stopwatch work? Glancing at the code for a few seconds, I saw some obvious problems right away.

Here is an example of the stopwatch being broken:

Bugfix 1

The first thing I noticed was on line 7:

class StopWatch extends React.Component {
  state = { lapse: 0, running: false };
  handleRunClick = () => {
    const startTime = Date.now() - this.state.lapse;
    setInterval(() => {
      this.setState({
        lapse: Date.now - startTime
      });
    });
    this.setState({
      running: true
    });
  };
Enter fullscreen mode Exit fullscreen mode

Date.now() needs parentheses. Date is an an object constructor with .now() being a method. When we click on the start button, React doesn't know what to do here; we aren't setting the state of lapse to be a number, which we expect. By adding the parentheses, we get the start button to work. No more NaNms.

But now we have another problem: the timer won't stop.

I also removed the console.log(Math.random()); because I felt it was unneeded.

Bugfix 2: Getting the Stopwatch to Stop and Clear

Each time the button is clicked, we set the state to either running or lapse. The timer runs when we click start but clicking stop or clear doesn't seem to work. How can we fix this?

We can create a timer update function that accepts the current state. We can accomplish this by using native DOM APIs such as setInterval() and clearInterval(). We can run conditional logic to see if the timer is running:

//updater function
this.setState(state => {
  if (state.running) {
    clearInterval(this.timer);
  } else {
    const startTime = Date.now() - this.state.lapse;
    this.timer = setInterval(() => {
      this.setState({
        lapse: Date.now() - startTime
      });
    });
  }
Enter fullscreen mode Exit fullscreen mode

and use Date.now() to get the timestamp in ms, assign it a startTime variable to compare the current time to the amount of time that has passed. When we click the start button, it sets the startTime to the current timestamp. We also need to return a new state as state is not mutable..

class StopWatch extends React.Component {
  state = { lapse: 0, running: false };
  handleRunClick = () => {
    //updater function
    this.setState(state => {
      if (state.running) {
        clearInterval(this.timer);
      } else {
        const startTime = Date.now() - this.state.lapse;
        this.timer = setInterval(() => {
          this.setState({
            lapse: Date.now() - startTime
          });
        });
      }
      // returning a new state to not mutate our original state
      return { running: !state.running };
    });
  };
Enter fullscreen mode Exit fullscreen mode

Okay so this partially works. But as you can see below, if I click clear while the stopwatch timer is running, it doesn't clear the timer, and it also doesn't allow me to stop the timer, either.

How do we fix this particular bug?

If we look back at the previous code, we can see we are using clearInterval() to reset the stopwatch timer. In our current iteration, our handleOnClear method is just setting the state without clearing the previous state.

handleOnClear = () => {
  this.setState({
    lapse: 0,
    running: false
  });
};
Enter fullscreen mode Exit fullscreen mode

We can fix this by adding clearInterval() and passing in the timer function to the handleOnClear method to clear the state.

handleOnClear = () => {
  clearInterval(this.timer);
  this.setState({
    lapse: 0,
    running: false
  });
};
Enter fullscreen mode Exit fullscreen mode

This will give us the results we want.

Potential Problem?

There is a memory leak in this particular iteration. The timer will run until it is explicitly stopped in the DOM. We can use a React lifecycle method to stop all processes in the DOM when this component is mounted or unmounted.

For this we can use componentWillUnmount to tell React to unmount the component once it is done rendering.

componentWillUnmount() {
  clearInterval(this.timer);
}
Enter fullscreen mode Exit fullscreen mode

Thoughts and Conclusions

I find it much more enjoyable fixing other people's bugs than my own. This was a fun exercise and I plan on doing it more regularly and blogging about it.

This stopwatch is a stupid simple component but if you are just scratching the surface of React like me, I am sure digging into something like this stopwatch and figuring out how it works is an excellent exercise and use of one's time.


Sign Up for the Newsletter. No spam. I hate that, too.

https://buttondown.email/tiffanywhite

Discussion

pic
Editor guide
Collapse
msarit profile image
Arit Amana

Excellent post! And this really encourages me, because I'm currently the opposite: delving into someone else's code intimidates me :)

Collapse
mrbenj profile image
Ben Junya

It might seem a little intimidating, but what's the worst that could happen? You break something and have to do git reset --hard head? The computer will not explode... Unless you do something really, really awesome. Then I would love to know how you made your computer explode.

You can do it!

Collapse
marissab profile image
Marissa B

Interesting post and great explanations. I'm torn on whether I enjoy troubleshooting someone else's code. At times it can be miserable depending on how much sauce was served with the spaghetti... But if it's finding fiddly little things like this it can be rewarding without being super tedious.

Collapse
tiffany profile image
Tiffany White Author

Agreed. It helps if you’re already familiar with the language, which I was. If it was something I was mildly familiar with I’d have probably felt differently for sure.

Collapse
daveskull81 profile image
dAVE Inden

Great article. This is an interesting idea to find other's code and dig through it to see how it works, or doesn't work in some cases. :) I imagine this is what it would be like to work on a team of devs and have to fix bugs in code you didn't write. I'm looking forward to more posts on this subject.

Collapse
mrbenj profile image
Ben Junya

Hey! This is awesome. Thank you for sharing your venture into getting into someone else's code :).

The more foreign the codebase, the more opportunities to learn. Keep on doing what you're doing.