Building a Coin-Tossing Simulator with React, Hooks, and Vercel: Part 1
I’ve never written a React tutorial before—there are plenty of people more qualified than me to do so—but I was recently reading “Why Does the World Exist?” by Jim Holt, which contained a passage that moved me to tinker with an idea:
Think of an infinite sequence of random coin tosses: 1 for “heads,” 0 for “tails.” Even though the sequence as a whole will be patternless, it is guaranteed to contain—by pure chance—all conceivable local patterns. There will be stretches of perfect fullness, consisting of a long run of 1’s. There will be stretches of perfect emptiness, consisting of a long run of 0’s.
Upon reading this, I thought it would be nice to visualise these coin tosses, seeing the longest streaks of heads-versus-tails, as well as how the average ends up over time.
Over a series of a handful of posts, I hope to walk through doing this in a simple React app, making use of React’s hooks, and deploying this little toy on a service called Now, allowing other people to run the simulation on their computers too.
Prerequisites
This post will assume at least a little knowledge about how to use the command
line. Nothing terribly complex; navigating between folders with cd
, and
installing things with npm
or yarn
.
Which brings me to the other prerequisite: you should make sure you have node and npm installed on your computer. I’m going to be using yarn, an alternative to npm, but for the most part, the two are interchangable:
yarn | npm |
---|---|
yarn add {package} | npm install {package} |
yarn start | npm start |
I’m also assuming you’re a little familiar with HTML, CSS, and JavaScript. You might have written a portfolio website, or tinkered with Neopets, or work closely with developers in your job. If you aren’t familiar with these languages, you might have a little difficulty following the post, but hopefully you can follow along and learn just enough to be dangerous.
Creating a React App
The first step is the simplest one, thanks to a tool called create-react-app. Assuming you have a recent version of node installed, open up the command line, navigate somewhere you’d like your app to live, and run the following command:
npx create-react-app coin-toss
This will create a new folder, coin-toss
, and populate it with all the code
you need to run an example React application. When the create-react-app
command is finished, it will instruct you to do the following:
cd coin-toss
yarn start
Go ahead and do that. You should see that a development server starts running,
and your browser should open and take you to a localhost
web page, where you
see the example React app running.
If you need to stop or restart the development server at any time, you can press
Ctrl + C
and then run yarn start
to begin it again.
Congratulations! Strictly speaking, you’ve just created your first React app! If running the example code has left you a little underwhelmed, don’t fret: next, we’ll start to write some custom code for our application.
The first thing we need to do in our app is have it simulate the basic exercise of tossing a coin. Let’s change our app so that it has a button to toss an imaginary coin and then tells us the result.
Step 1: Removing The Example Code
Open up the coin-toss
folder in your code editor of choice (I’m using
Visual Studio Code) and you should see the
following contents:
node_modules
public
src
↳ App.css
↳ App.js
↳ App.test.js
↳ index.css
↳ index.js
↳ logo.svg
↳ serviceWorker.js
.gitignore
package.json
README.md
yarn.lock
Open up src/App.js
. We’re going to delete most of the code already inside it,
but feel free to copy-and-paste if it’s easier.
We’ll delete some of the import statements at the top and most of the code in
the App
function. Here’s what your App.js
should look like:
import React from "react"
function App() {
return <div>The coin toss app will go here!</div>
}
export default App
If the development server is still running, in your web browser you should now see that your app is just a page that says “The coin toss app will go here!”.
Since we deleted the references to logo.svg
and App.css
in App.js
, we can
also delete those files:
node_modules
public
src
- ↳ App.css
↳ App.js
↳ App.test.js
↳ index.css
↳ index.js
- ↳ logo.svg
↳ serviceWorker.js
.gitignore
package.json
README.md
yarn.lock
Interlude: Understanding React’s JSX Syntax: Let’s go back to App.js
for a
moment. If you haven’t seen React code before, seeing HTML-like bracketed-code
might be a surprise to you:
import React from "react"
function App() {
return <div>The coin toss app will go here!</div>
}
export default App
This is called JSX syntax, and it’s just a convenient way of writing React code. The line above could also be written like this:
return React.createElement("div", null, "The coin toss app will go here!")
When we write <div>
in JSX, it’s telling React to create a div
element,
without any additional properties or attributes (“props” in React), with “The
coin toss app will go here!” as its contents (or “children”).
The create-react-app
command, in addition to providing us with some starter
code, also enabled us to write JSX syntax so that we didn’t have to write
functions like above.
Step 2: Adding The “Toss Coin” Button
Let’s add the “toss coin” button to our app. We can place a button inside the
div
already in our code. Let’s update the App
function like so:
function App() {
return (
<div>
The coin toss app will go here!
<button>Toss coin</button>
</div>
)
}
Save your changes and check the web browser: we now have a button, but clicking it doesn’t do anything yet. Let’s change that:
function App() {
const tossCoin = () => {
alert("The coin was tossed")
}
return (
<div>
The coin toss app will go here!
<button onClick={tossCoin}>Toss coin</button>
</div>
)
}
Now, when you click the button, the browser should show a dialog that says “The coin was tossed”.
In addition to having the tossCoin
function, we need to actually have our
virtual coin so that we can tell which side it landed on. Like the excerpt from
the book at the start of the page, we’ll represent the sides with a 1 for
“heads” and a 0 for “tails”.
To manage our coin, we’ll use something called the useState
hook. A “hook”
in React is just a function that takes advantage of React’s “component
lifecycle”, which determines when a component or an app should update.
useState
lets us define a variable and provides a function for updating that
variable later on. We’ll need one for the coin’s side, and one for the number of
times the coin has been tossed.
import React from "react"
const { useState } = React
function App() {
const [side, setSide] = useState(1)
const [tossed, setTossed] = useState(0)
const tossCoin = () => {
const landedOn = Math.round(Math.random())
setSide(landedOn)
setTossed(tossed + 1)
}
return (
<div>
<p>The coin has been tossed {tossed} times.</p>
<p>It landed on {side === 1 ? "heads" : "tails"}</p>
<button onClick={tossCoin}>Toss coin</button>
</div>
)
}
export default App
Let’s walk through the changes we just made.
const { useState } = React
This might be unfamiliar syntax again. This is called object destructuring1, and it’s the same as writing:
const useState = React.useState
This code makes the useState
hook available in App.js
. Next, we update the
tossCoin
function to use the hook and set some new variables:
const [side, setSide] = useState(1)
const [tossed, setTossed] = useState(0)
This might be new as well! This is another form of destructuring. The useState
function returns an array of two values: the state variable, and the function to
update the state variable. The first line above can be re-written as:
const result = useState(1)
const side = result[0]
const setSide = result[1]
Looking back to the previous code sample, we’re setting four new variables:
side
, which will initially be1
setSide
tossed
, which will initially be0
- and
setTossed
We’ll use the side
and tossed
variables to keep track of which side of the
coin we see and how many times it’s been tossed, and setSide
and setTossed
to update them respectively.
Our tossCoin
function has been updated too:
const tossCoin = () => {
const landedOn = Math.round(Math.random())
setSide(landedOn)
setTossed(tossed + 1)
}
landedOn
is set to either 1 or 0. The Math.random
function will return a
random floating point number between 0 and 1, so we just take that value and
round it to the nearest whole number.
Next, we call the setSide
function with our landedOn
value to tell our app
which side of the coin we see, and setTossed
to increase the tossed
value
by 1.
Finally, the return
value of App
has been updated to show two paragraphs:
<p>The coin has been tossed {tossed} times.</p>
<p>It landed on {side === 1 ? "heads" : "tails"}</p>
Here, we’re using the tossed
variable to indicate how many times we’ve tossed
our virtual coin. The curly braces are there to tell React/JSX that we’d like to
use a JavaScript variable.
In the next paragraph, we’re checking if the side
variable is equal to 1
. If
it is, we’ll output “heads”, and if it isn’t, we’ll output “tails”.
Putting all of this together, we can now go back to the browser and click the “Toss coin” button, and it will update with the number of times it’s been tossed, along with which side of the coin is seen. If you keep pressing the button, you’ll already start to see some of the patterns mentioned in the excerpt: long sequences of 0’s, followed by long sequences of 1’s, followed by interwoven 0’s and 1’s.
If you’ve made it this far, you should feel proud! We’ve made a React app that responds to user input and dynamically updates.
Part 1 Conclusion: The Power of React: If you’re like me, it’s probably taking (or did take) a while to warm up to the idea of React. Why would I prefer it over regular JavaScript or jQuery? Why does it seem so different from everything else I’ve learned about JavaScript?
Hopefully by following this tutorial you’ve started to feel a little of React’s power come into play. What I’ve found really appealing about React is that it is
declarative and it is reactive.
By declarative, I mean that rather than describing the steps you take to make an element or a variable a certain way, you just describe the element straight away. Let’s look at an example in classic JavaScript:
const button = document.createElement("button")
button.innerHTML = "Toss coin"
button.addEventListener("click", tossCoin)
And compare it to the JSX/React code:
<button onClick={tossCoin}>Toss coin</button>
Especially in larger codebases, writing declarative UI code like this can make managing the codebase much easier.
Secondly, when I say reactive, I’m describing one of the side effects of declarative code, and a feature that React in particular makes available to us.
Notice how in our application, because we’re writing our code declaratively, and
we’re letting React handle many of our variables using useState
, we don’t have
to manually update variables like side
or tosses
, and we don’t have to
change any inner HTML of the paragraph elements of our app. In classic JS, we’d
likely have to update a lot of things ourselves:
const firstParagraph = document.createElement("p")
firstParagraph.innerHTML = `The coin has been tossed ${tossed} times.`
// ...much later or elsewhere in our code
tossed = tossed + 1
firstParagraph.innerHTML = `The coin has been tossed ${tossed} times.`
By writing our code declaratively with the help of React, we need only write our
paragraph once, and everything updates automatically whenever tossed
or other
variables change or update.
In the next part of this series, we’ll start to count the total number of times that each side of the coin appears, and visualise them using HTML elements. We’ll also have our coin flipped automatically for us, so that you don’t have to press a button each time.
While waiting for the next post, consider how you might achieve those next steps yourself, or what other creative ways you could use what you’ve learned in this first part.
Thanks for reading, and be sure to follow me on Twitter to find out when the next post is available, and to ask for anything specific you’d like to see in the future posts!
Footnotes
-
You can learn more about destructuring assignments from the MDN JavaScript documentation ↩