Phase 5: Fruit Form

Understand the Problem

We need a form to collect data for a new fruit. The form should have validation to ensure proper input, and when submitted, it should print the data to the console and navigate back to the home page. The inputs must be controlled, meaning the form fields are connected to state variables.

Devise a Plan

  1. Create state variables for name, color, sweetness, seeds, and errors
  2. Render a form with inputs and update state on change
  3. Validate the form before submitting
  4. Log the form data and use navigate to go back to the homepage

Carry Out the Plan

File: src/FruitForm.jsx

// Pseudocode:
// 1. Create state for each field
// 2. Handle input changes and update state
// 3. Validate inputs on submit
// 4. If valid, log and navigate home

import { useState } from 'react';
import { useNavigate } from 'react-router-dom';

const COLORS = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'];

function FruitForm({ fruits }) {
  const navigate = useNavigate();
  const [name, setName] = useState('');
  const [color, setColor] = useState('orange');
  const [sweetness, setSweetness] = useState(1);
  const [seeds, setSeeds] = useState('yes');
  const [errors, setErrors] = useState([]);

  const validate = () => {
    const errs = [];
    if (name.length < 3) errs.push('Name must be 3 or more characters');
    if (name.length > 20) errs.push('Name must be 20 characters or less');
    if (fruits.some(f => f.name.toLowerCase() === name.toLowerCase())) errs.push('Name already exists');
    if (sweetness < 1 || sweetness > 10) errs.push('Sweetness must be between 1 and 10');
    setErrors(errs);
    return errs.length === 0;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!validate()) return;
    console.log({ name, color, sweetness, seeds });
    navigate('/');
  };

  return (
    <form className="fruit-form" onSubmit={handleSubmit}>
      <h2>Enter a Fruit</h2>
      {errors.map((err, i) => (
        <p key={i} className="errors">{err}</p>
      ))}

      <label>
        Name
        <input
          type="text"
          value={name}
          onChange={e => setName(e.target.value)}
        />
      </label>

      <label>
        Select a Color
        <select value={color} onChange={e => setColor(e.target.value)}>
          {COLORS.map(c => (
            <option key={c} value={c}>{c}</option>
          ))}
        </select>
      </label>

      <label>
        Sweetness
        <input
          type="number"
          value={sweetness}
          onChange={e => setSweetness(Number(e.target.value))}
        />
      </label>

      <label>
        <input
          type="radio"
          value="no"
          checked={seeds === 'no'}
          onChange={e => setSeeds(e.target.value)}
        /> No Seeds
      </label>

      <label>
        <input
          type="radio"
          value="yes"
          checked={seeds === 'yes'}
          onChange={e => setSeeds(e.target.value)}
        /> Seeds
      </label>

      <button type="submit" disabled={errors.length > 0}>Submit Fruit</button>
    </form>
  );
}

export default FruitForm;

Expected Input and Output

Explanation for New Developers

This form uses the useState hook to track each input field. It’s called a “controlled form” because React controls what’s inside each input based on state.

On submit, we check the inputs using a validate function. If everything looks good, we log the values and send the user back to the home page using navigate.

Real World Analogy

This is like filling out a registration form. If you miss a required field, it won’t let you submit. Once you complete all the fields, your info is saved and you're redirected.

Bonus Tip

Try customizing validation error messages or adding real-time validation as the user types.