React Prime Number Finder - JavaScript Exercise #1

React Prime Number Finder - JavaScript Exercise #1

ยท

6 min read

Create a simple React component that takes in a number as input and returns a list of all the prime numbers that are less than or equal to the input number.

Before you dive into the final output, I want to encourage you to take some time to work through the exercise yourself. I believe that active learning is the most effective way to learn and grow as a developer.

So, grab a pen and paper, fire up your code editor, and get ready to dive into the React Prime Number Finder exercise. Once you have completed the exercise, feel free to return to this blog post to compare your solution to mine.

Exercise implementation:

import React, { useState } from 'react';

function PrimeNumberList() {
  const [inputValue, setInputValue] = useState('');
  const [primeNumbers, setPrimeNumbers] = useState([]);

  const handleInputChange = (event) => {
    setInputValue(event.target.value);
  };

  const handleButtonClick = () => {
    const inputNumber = parseInt(inputValue);
    const primes = [];

    for (let i = 2; i <= inputNumber; i++) {
      let isPrime = true;

      for (let j = 2; j < i; j++) {
        if (i % j === 0) {
          isPrime = false;
          break;
        }
      }

      if (isPrime) {
        primes.push(i);
      }
    }

    setPrimeNumbers(primes);
  };

  return (
    <div>
      <input type="text" value={inputValue} onChange={handleInputChange} />
      <button onClick={handleButtonClick}>Find Primes</button>
      <ul>
        {primeNumbers.map((prime) => (
          <li key={prime}>{prime}</li>
        ))}
      </ul>
    </div>
  );
}

export default PrimeNumberList;

In this example, the component uses the useState hook to manage two pieces of state: the input value (inputValue) and the list of prime numbers (primeNumbers).

The handleInputChange function is called whenever the user types in the input field and updates the inputValue state to reflect the new value.

The handleButtonClick function is called when the user clicks the "Find Primes" button. It uses a simple algorithm to find all the prime numbers less than or equal to the input value and sets the primeNumbers state to the resulting array.

Finally, the component renders the input field, button, and a list of the prime numbers. The map function is used to generate the list of items from the primeNumbers array.

You can modify the input element to only accept numbers by setting the type attribute to "number". You can also add the min attribute to ensure that only positive numbers are accepted.

Here's the modified code for the input element:

<input type="number" value={inputValue} onChange={handleInputChange} min={1} />

By setting the type attribute to "number", the input field will only accept numerical input. And by setting the min attribute to 1, we ensure that only positive numbers are allowed.

Additionally, you can add some validation to the handleInputChange function to ensure that the input value is a valid number. Here's an updated version of that function:

const handleInputChange = (event) => {
  const input = event.target.value;

  if (input === '' || /^[0-9\b]+$/.test(input)) {
    setInputValue(input);
  }
};

In this updated function, we use a regular expression to test whether the input value consists of only digits. If it does, we update the state with the new input value. If not, we do nothing.

The \b in the regular expression matches a backspace character, which allows the user to delete characters from the input field.

One issue that can arise with the current implementation is that if the user enters a very large number, the algorithm used to find prime numbers will take a long time to execute, potentially causing the browser to become unresponsive.

To address this issue, we can modify the algorithm to use a more efficient approach for finding prime numbers, such as the Sieve of Eratosthenes. This algorithm works by creating a boolean array of size n+1, where n is the input number and initially sets all elements to true. We then iterate over the array, starting from 2, and for each prime number we mark all of its multiples as false. The remaining true elements in the array are the prime numbers.

Here's an updated version of the handleButtonClick function that uses the Sieve of Eratosthenes algorithm:

const handleButtonClick = () => {
  const inputNumber = parseInt(inputValue);

  if (isNaN(inputNumber) || inputNumber <= 1) {
    setPrimeNumbers([]);
    return;
  }

  const primes = [];
  const isPrime = Array(inputNumber + 1).fill(true);

  isPrime[0] = false;
  isPrime[1] = false;

  for (let i = 2; i <= Math.sqrt(inputNumber); i++) {
    if (isPrime[i]) {
      for (let j = i * i; j <= inputNumber; j += i) {
        isPrime[j] = false;
      }
    }
  }

  for (let i = 2; i <= inputNumber; i++) {
    if (isPrime[i]) {
      primes.push(i);
    }
  }

  setPrimeNumbers(primes);
};

In this updated function, we first check whether the input value is a valid number and greater than 1. If not, we set the primeNumbers state to an empty array and return early.

If the input value is valid, we create an array isPrime of size n+1 and fill it with true. We then iterate over the array, starting from 2, and for each prime number we mark all of its multiples as false. Finally, we iterate over the array again and add all the true elements to the primes array, which we then set as the primeNumbers state.

By using the Sieve of Eratosthenes algorithm, we can efficiently find all the prime numbers less than or equal to the input value, even for very large inputs.

Here's the final code that addresses both the input validation and performance issues

import React, { useState } from "react";

const PrimeNumberList = () => {
  const [inputValue, setInputValue] = useState("");
  const [primeNumbers, setPrimeNumbers] = useState([]);

  const handleInputChange = (event) => {
    const input = event.target.value;

    if (input === '' || /^[0-9\b]+$/.test(input)) {
      setInputValue(input);
    }
  };

  const handleButtonClick = () => {
    const inputNumber = parseInt(inputValue);

    if (isNaN(inputNumber) || inputNumber <= 1) {
      setPrimeNumbers([]);
      return;
    }

    const primes = [];
    const isPrime = Array(inputNumber + 1).fill(true);

    isPrime[0] = false;
    isPrime[1] = false;

    for (let i = 2; i <= Math.sqrt(inputNumber); i++) {
      if (isPrime[i]) {
        for (let j = i * i; j <= inputNumber; j += i) {
          isPrime[j] = false;
        }
      }
    }

    for (let i = 2; i <= inputNumber; i++) {
      if (isPrime[i]) {
        primes.push(i);
      }
    }

    setPrimeNumbers(primes);
  };

  return (
    <div>
      <label>
        Enter a number:
        <input
          type="number"
          value={inputValue}
          onChange={handleInputChange}
          min={1}
        />
      </label>
      <button onClick={handleButtonClick}>Generate primes</button>
      <ul>
        {primeNumbers.map((number) => (
          <li key={number}>{number}</li>
        ))}
      </ul>
    </div>
  );
};

export default PrimeNumberList;

Here's the TypeScript version of the final code

import React, { useState } from "react";

const PrimeNumberList: React.FC = () => {
  const [inputValue, setInputValue] = useState<string>("");
  const [primeNumbers, setPrimeNumbers] = useState<number[]>([]);

  const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const input = event.target.value;

    if (input === '' || /^[0-9\b]+$/.test(input)) {
      setInputValue(input);
    }
  };

  const handleButtonClick = () => {
    const inputNumber = parseInt(inputValue);

    if (isNaN(inputNumber) || inputNumber <= 1) {
      setPrimeNumbers([]);
      return;
    }

    const primes: number[] = [];
    const isPrime: boolean[] = Array(inputNumber + 1).fill(true);

    isPrime[0] = false;
    isPrime[1] = false;

    for (let i = 2; i <= Math.sqrt(inputNumber); i++) {
      if (isPrime[i]) {
        for (let j = i * i; j <= inputNumber; j += i) {
          isPrime[j] = false;
        }
      }
    }

    for (let i = 2; i <= inputNumber; i++) {
      if (isPrime[i]) {
        primes.push(i);
      }
    }

    setPrimeNumbers(primes);
  };

  return (
    <div>
      <label>
        Enter a number:
        <input
          type="number"
          value={inputValue}
          onChange={handleInputChange}
          min={1}
        />
      </label>
      <button onClick={handleButtonClick}>Generate primes</button>
      <ul>
        {primeNumbers.map((number) => (
          <li key={number}>{number}</li>
        ))}
      </ul>
    </div>
  );
};

export default PrimeNumberList;

Thanks for taking this JavaScript exercise!

I hope this JavaScript exercise will help you unlock the full potential of React and build high-performance web applications.

If you have any questions or comments, feel free to reach out to me on Twitter(@rajeshtomjoe), or follow me for more updates.

And if you'd like to receive more exercise on JavaScript, be sure to subscribe to my blog.

ย