React forms
Learn how to build dynamic interactions using form elements in React
Last updated
Learn how to build dynamic interactions using form elements in React
Last updated
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.
Download starter files and cd
in
Run npm install
Run npm run dev
to start the dev server
Since React uses non-standard syntax (JSX) it requires some processing before it can run in the browser. We'll use Vite for this. Vite also provides a nice dev server that will auto-reload when you change files.
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.
JSX supports multiple child elements like this:
This is the same as listing those child elements in an array, like this:
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:
It's common to inline the .map()
(although using a separate named variable is fine if you find it clearer):
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.
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:
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 range inputs.
It can be a good idea to group and label related elements using the fieldset element.
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.
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:
Now we need to filter our dish list based on the price state.
You should have something like this:
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.
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:
You should end up with something like this:
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 🎉
Add a default "All" option to the category filter
Add a text input that lets users search for dishes by title
Make it look even better 💅