LogoLogo
  • FAC Curriculum
  • archive
    • Node & npm introduction
    • developer
      • Programming Paradigms
    • handbook
      • Asking for help
      • Coaching groups
      • Code review
      • Course rules
      • Debugging
      • Employment schedule and material delivered in FAC20
      • GitHub Workflow
      • Glossary or terms
      • Presentation Guidance
      • Equality, Diversity and Inclusion
      • Installation guide
      • Learning circles
      • Mentoring guidance
      • What to expect from your mentors
      • One-day projects
      • Pair programming
      • Portfolio
      • Questions for problem solving
      • Progress Logs
      • Final project report
      • Managing software projects
      • Project Presentations
      • Project roles
      • Projects
      • Retrospectives
      • Role Circles
      • Safeguarding policy
      • Technical Spikes
      • System requirements
      • Tech for Better
      • User Manuals
      • Wellbeing Support
      • project-docs
        • What makes a mentor?
        • Product Handover
        • Sprint Planning
        • Tech for Better Presentations
        • User Research & Usability Testing
    • foundation
      • full-stack
        • Learning Outcomes
        • project
      • testing
        • project
        • spikes
  • docs
    • Contributing to the curriculum
    • Curriculum intent
    • Curriculum process
  • src
    • About our curriculum
    • course
      • Code of Conduct
      • Docker
      • .NET and Umbraco
      • Getting started
      • Founders and Coders coursebook
      • KSB's
      • Mini projects
      • Revision checklist
      • Svelte
      • TypeScript
      • handbook
        • Software Developer Handbook
        • Software Foundation Handbook
      • precourse
        • Before you start the course
        • Installation List
      • syllabus
        • developer
          • app
            • learning-outcomes
            • project
            • schedule
            • spikes
          • introduction
            • learning-outcomes
            • project
            • resources
            • schedule
          • week00-pre-course
            • We'd like you to spend some time before starting the course working on useful fundamentals.
            • spikes
          • week01-project01-basics
            • Employability introduction
            • Homework
            • learning-outcomes
            • Week of September 9th
            • project
            • resources
            • schedule
            • spikes
          • week02-project02-chatbot
            • employability
            • Homework
            • learning-outcomes
            • Week of September 16th
            • project
            • resources
            • schedule
            • spikes
          • week03-project03-server
            • Learning Outcomes
            • Week of September 23th
            • The Amazin' Quizzer API Backend
            • resources
            • schedule
          • week04-project03-frontend
            • learning-outcomes
            • Week of September 30th
            • UI for Quizzer App
            • resources
            • schedule
          • week05-project03-test-deploy
            • Testing and deployment
            • Week of October 7th
            • project
            • resources
            • schedule
          • week06-project04-databases
            • learning-outcomes
            • Week of October 14th
            • project
            • Databases
            • schedule
          • week07-project04-authentication
            • Learning Outcomes
            • Week of October 21st
            • project
            • resources
            • schedule
          • week08-project04-test-deploy
            • Learning Outcomes
            • Week of October 28th
            • project
            • resources
            • schedule
          • week09-reading-week
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
          • week10-project05-DOTNET-intro
            • Learning Outcomes
            • overview
            • project
            • Resources
            • schedule
          • week11-project05-DOTNET-testing
            • Testing and deployment
            • Week of November 18th
            • project
            • Resources
            • schedule
          • week12-project05-DOTNET-deploy
            • Learning Outcomes
            • Week of November 25th
            • project
            • Resources
            • schedule
            • Spikes
          • week13-TFB-design
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
            • Design Week Spikes
          • week14-TFB-build
            • Learning Outcomes
            • overview
            • Project
            • DevOps Resources
            • schedule
            • Spikes
          • week15-TFB-build
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
            • Spikes
          • projects
            • in-house-design
              • Learning Outcomes
              • Project
              • Resources
              • schedule
              • Design Week Spikes
        • foundation
          • Obsolete-full-stack
            • project
          • post-course
            • Homework
            • schedule
        • portfolio
          • fruit-shop
            • learning-outcomes
            • project
            • resources
          • game
            • learning-outcomes
            • project
            • resources
          • hobby-page
            • learning-outcomes
            • project
            • resources
          • movie-data
            • learning-outcomes
            • project
            • resources
          • project-gallery
            • learning-outcomes
            • project
            • resources
          • website
            • learning-outcomes
            • project
            • JavaScript
        • tfb
          • week 1
            • Introduction (45 minutes)
            • Further reading
          • week 10
            • content
            • resources
          • week 11
            • What will we be doing this week?
            • resources
          • week 12
            • What will we be doing this week?
            • Further reading
          • week 2
            • Discover (90 minutes)
            • resources
          • week 3
            • content
            • resources
          • week 4
            • Mapping the user journey (90 minutes)
            • resources
          • week 5
            • Figma Workshop 1 (90 minutes)
            • Further reading
          • week 6
            • Figma Workshop 2 (90 minutes)
            • resources
          • week 7
            • Product pitches & Selection (90 minutes)
            • resources
          • week 8
            • content
            • resources
          • week 9
            • content
            • resources
    • learn
      • DOTNET
        • Introduction to .NET
      • auth
        • Authenticating web apps
      • database
        • Persisting data with SQLite and Node
      • dotnet-two
        • Dependency injections and interfaces in .NET
      • form-validation
        • Form validation
      • react
        • Building client-side apps with React
      • server
        • HTTP servers with Node & Express
      • typescript
        • TypeScript
    • mentoring
      • design-week
        • Analysis Workshop
        • Code planning
        • Definition Workshop
        • Discovery Workshop
        • Figma introduction
        • Usability testing
        • User Research
    • resources
      • http
        • introduction
    • workshops
      • cookie-auth
        • index
      • creating-promises
        • index
      • css-layout
        • index
      • cypress-testing
        • index
      • database-testing
        • index
      • dev-tooling
        • Developer tooling
      • dom-challenge
        • index
      • dom-rendering
        • index
      • es-modules
        • index
      • express-middleware
        • Express middleware
      • first-class-functions
        • index
      • form-validation
        • index
      • functions-callbacks-async
        • Functions, callbacks, & async JavaScript
      • git-intro
        • Introduction to Git
      • git-terminal
        • Using Git in the terminal
      • git-workflow
        • Git workflow
      • github-projects
        • GitHub Projects Workflow Workshop
      • heroku-sql-challenge
        • index
      • html-forms
        • index
      • learn-a11y
        • index
        • starter-files
          • solution
            • Accessibility solution explanation
      • learn-fetch
        • index
      • learn-integration-testing
        • index
      • learn-testing
        • Learn testing in JavaScript
      • learn-unit-testing
        • index
      • node-error-handling
        • Node error-handling
      • node-express-server
        • Node and Express HTTP server
      • node-npm-intro
        • Node & npm introduction
      • node-postgres
        • Learn Postgres with Node
      • node-scripting-challenge
        • index
      • password-security
        • index
      • promise-practice
        • index
      • react-components
        • React components
      • react-fetch
        • index
      • react-forms
        • React forms
      • react-refactor-classes
        • index
      • react-state-effects
        • React state & effects
      • real-world-fetch
        • index
      • scope-challenge
        • Scope debugging challenge
      • semantic-html
        • index
      • server-side-forms
        • Server-side forms
      • session-auth
        • Session authentication
      • sql-intro
        • index
      • tdd-array-methods
        • index
Powered by GitBook
On this page
  • Part 1: Project setup
  • Part 2: Render a list
  • Part 3: Create price inputs
  • Part 4: Filter list by price
  • Part 5: Modularise your components
  • Part 6: Create radio group
  • Part 7: Filter list by category
  • Stretch goals
Export as PDF
  1. src
  2. workshops
  3. react-forms

React forms

Learn how to build dynamic interactions using form elements in React

Previousreact-formsNextreact-refactor-classes

Last updated 2 years ago

We're going to build a simplified food delivery menu page. It'll have a list of dishes plus a form to filter them. The final result should look something like this:

Don't worry, we'll work our way there step by step.

Part 1: Project setup

  1. Download starter files and cd in

  2. Run npm install

  3. Run npm run dev to start the dev server

Open workshop/index.jsx in your editor. This is where we render our React app to the DOM. You can see that we have a top-level component named App. Open App.jsx to see what's currently being rendered.

Part 2: Render a list

JSX supports multiple child elements like this:

function App() {
  return (
    <ul>
      <li>Apple</li>
      <li>Orange</li>
      <li>Banana</li>
    </ul>
  );
}

This is the same as listing those child elements in an array, like this:

function App() {
  return <ul>{[<li>Apple</li>, <li>Orange</li>, <li>Banana</li>]}</ul>;
}

This isn't very ergonomic to write by hand, but it comes in handy when you need to render a dynamic list. We can generate an array from some data and render it:

function App() {
  const fruits = ["Apple", "Orange", "Banana"];
  const fruitList = fruits.map((fruit) => <li key={fruit}>{fruit}</li>);
  return <ul>{fruitList}</ul>;
}

It's common to inline the .map() (although using a separate named variable is fine if you find it clearer):

function App() {
  const fruits = ["Apple", "Orange", "Banana"];
  return (
    <ul>
      {fruits.map((fruit) => (
        <li key={fruit}>{fruit}</li>
      ))}
    </ul>
  );
}

We're passing a special prop called key to the top-level element in our array. This allows React to keep track of where each element is so it doesn't mess up the order. key should be unique and not change when the array order does. React will warn you if you forget this.

Task

Uncomment the line importing "../data.js". This is an array of objects, each representing a dish in our restaurant. Use .map to render all of them to the page inside the ul.

Take a look at what data you have available for each dish and try to render it all. You should end up with something like this:

Part 3: Create price inputs

<fieldset>
  <legend>Price</legend>
  <label htmlFor="min-price">
    Min price
    <input type="range" id="min-price" min="0.5" max="9" step="0.25" />
  </label>
  // ...
</fieldset>

Range inputs support constraining their values with the min/max/step attributes.

If we want these inputs to filter the list of dishes we'll need some state they can both use. For example we can create a state value called min that we update whenever the range input changes. Later we will be able to use the same min value to filter the dishes. By sharing the state value they'll always be in-sync.

function App() {
  const [min, setMin] = React.useState(0);
  return (
    // ...
    <fieldset>
      <legend>Price</legend>
      <label htmlFor="min-price">
        Min price
        <input
          type="range"
          id="min-price"
          min="0.5"
          max="9"
          step="0.25"
          value={min}
          onChange={(event) => setMin(event.target.value)}
        />
      </label>
      // ...
  );
}

Add the second range input for the maximum price. You'll need another state variable to control the input's value.

You should end up with something like this:

Part 4: Filter list by price

Now we need to filter our dish list based on the price state.

You should have something like this:

Part 5: Modularise your components

Our App component is starting to get a bit unwieldy. We've got a single function containing all our state, plus two totally separate sections of the page. Let's try splitting it up into a couple of smaller components.

Create two new files: DishList.jsx and PriceFilter.jsx. DishList.jsx should contain the <ul> of dishes; PriceFilter.jsx should contain the fieldset with the range inputs.

Remember these components need to share the same state. This means we can't define it down in each child component—the state needs to live in their shared parent (App) and be passed down to each child via props.

Part 6: Create radio group

We also want to filter our dishes by category. This is a good use-case for a group of radio inputs, since the categories are mutually exclusive.

Create a new file called CategoryFilter.jsx and make a new component in it. We need a radio input for each category.

You'll also need to create a state value to keep track of which radio is selected. Since this state will be needed to filter the DishList component it will need to live in their shared parent (App) and be passed down as a prop (just like the min/max state).

You can use the checked prop to determine which radio should be checked, based on the current state value. Here's an example:

<label htmlFor="burger">
  Burger
  <input
    type="radio"
    name="categories"
    id="burger"
    value="burger"
    checked={someStateVar === "burger"}
    onChange={(event) => setSomeStateVar(event.target.value)}
  />
</label>

You should end up with something like this:

Part 7: Filter list by category

Now we need to filter our list by category as well as the existing price filters. Use your category state value to filter the array in DishList. Make sure you keep the price filter working.

If everything is hooked up correctly you should see something like this 🎉

Stretch goals

  1. Add a default "All" option to the category filter

  2. Add a text input that lets users search for dishes by title

  3. Make it look even better 💅

Since React uses non-standard syntax (JSX) it requires some processing before it can run in the browser. We'll use for this. Vite also provides a nice dev server that will auto-reload when you change files.

We want to be able to filter the list of dishes by minimum and maximum price. To do this we'll need to create two .

It can be a good idea to group and label related elements using the element.

Vite
range inputs
fieldset
burger-place
initial app
part 2 example
part 3 example
part 4 example
part 6 example
burger-place