React is an easy to use JavaScript framework that lets us create front end apps.
In this article, we’ll look at how to create a typing test with React and JavaScript.
Create the Project
We can create the React project with Create React App.
To install it, we run:
npx create-react-app typing-test
with NPM to create our React project.
Create the Typing Test
To create the typing test, we write:
import React, { useEffect, useMemo, useState } from "react";
const text =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus sit amet tellus tortor. ";
export default function App() {
const [textToType] = useState(text);
const [typedText, setTypedText] = useState("");
const [timer, setTimer] = useState();
const [elapsedMs, setElapsedMs] = useState(0);
const [started, setStarted] = useState(false);
const [wpm, setWpm] = useState(0);
const parts = useMemo(() => {
const splitTextToType = textToType.split("");
let endIndexMatch = 0;
for (const [index, s] of splitTextToType.entries()) {
if (s !== typedText[index]) {
endIndexMatch = index;
break;
}
}
return {
matchedPart: textToType.slice(0, endIndexMatch),
unmatchedPart: textToType.slice(endIndexMatch)
};
}, [textToType, typedText]);
const start = () => {
const timer = setInterval(() => {
setElapsedMs((elapsedMs) => elapsedMs + 1);
if (!started) {
setStarted(true);
}
}, 1000);
setTimer(timer);
};
const restart = () => {
setStarted(started);
setElapsedMs(0);
setTypedText("");
};
useEffect(() => {
if (parts.unmatchedPart.length === 1) {
clearInterval(timer);
setWpm(textToType.split(" ").length / (elapsedMs / (60 * 1000)));
}
}, [parts, textToType, timer, elapsedMs]);
if (parts.unmatchedPart.length > 1) {
return (
<div>
<div>
<b>{parts.matchedPart}</b>
{parts.unmatchedPart}
</div>
<button onClick={start}>start</button>
<textarea
disabled={!started}
value={typedText}
onChange={(e) => setTypedText(e.target.value)}
style={{ width: "90vw", height: "300px" }}
></textarea>
</div>
);
} else {
return (
<div>
Your words per minute is {wpm}
<button onClick={restart}>restart</button>
</div>
);
}
}
We define the textToType
state with the text we type in to finish the test.
typedText
has the text we typed in.
timer
has the timer for the typing test.
elaspedMs
sets the elapsed time in milliseconds.
started
sets whether the test has started.
wpm
has the words per minute achieved.
Next we create the parts
variable with the useMemo
hook.
Its callback returns an object with the parts that we typed in and the parts we didn’t type yet.
matchedPart
has the part we typed in.
unmatchedPart
has the part we didn’t type in yet.
We get the matchedPart
by computing the last index where the text we typed in matched what’s in the text
string.
We split the textToType
string and store it in splitTextToType
Then we loop through splitTextToType
and get the first index of typedText
that doesn’t match the splitTextToType
array.
Next, we define the start
function which starts the test.
We call setInterval
to create the timer that sets the elaspedMs
state.
It also sets the started
state it’s set to false
.
The callback runs every second.
We call setTimer
to set the timer
value.
The restart
function just resets the values to the initial values.
In the useEffect
callback, we check the parts.unmatchedPart
property’s length and clear the timer with clearInterval
is unmatchedPart
is 1.
And we call setWpm
to set the words per minute.
The 2nd array has the reactive states we’re watching and the callback runs whenever any of them changes.
Then we check if the test is finished with parts.unmatchedPart.length > 1
.
If parts.unmatchedPart.length > 1
is true
, then the test isn’t finished so we render the typed and untyped text.
Then we render the button to let ys start the test.
And we have a text area to let the user type the test.
We disable the text area if started
is false
.
And we get and set the typed value with value
and onChange
.
Otherwise, the test is done and we show the words per minute and a button that we can click to restart the test.
Conclusion
We can create a typing test easily with React and JavaScript.