Categories
React Projects

Create a Typing Test with React and JavaScript

Spread the love

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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *