Version: 2021sp

Assignment 5

For A5, you'll be building a React app that utilizes conditional rendering and the concept of lifting state up.

In this project, we'll be building a searchable or filterable grocery list that maintains a list of items, each with its own metadata. This metadata simply consists of the name of the item, as well as its price. The app is composed out of a few components: one that maintains each grocery item itself, one that renders the list of grocery items, and one that acts as a search bar for us to filter and search through our list of items, rerendering the list of grocery items. There will also be some helper text depending on the state of items in the grocery list. You will need to use lifting state up and conditional rendering in order to accomplish all of this.

Here is a GIF showing the final functionality of the app:

Assignment 5 Demo

Part 1 - App.tsx Scaffolding#

In App.tsx, we will have two states, as well as a type definition to be exported to other components. Let's start with the type definition. We want to make a type for each item's metadata (remember, each item has a string name and a price that is a number). When you define this, make sure to put the export keyword before the type definition so that you can import it in other components that need to use it.

Next, create the two states, each of which will be lifted up from a child component. The first state should represent all of the items (metadata) on the list, and the second should keep track of the current search query string. Do not display the list in this component; we will be passing it down to a child component.

Part 2 - Lifting State Up#

Create two components: SearchBar.tsx and AddItemBar.tsx. The first one will have an <input> field representing the search bar, and will need to lift the value of the input up into the App.tsx parent. The second one will have two input fields: one for the name of the item, and the second for the price, as well as a button to actually submit the data in the two fields to the list. The button onClick prop will be useful for implementing this, as well as maintaining two internal states for the name and price values in AddItemBar.

Once you've created these child components, add them to App.tsx and supply them with the necessary props. Assuming you've lifted state up correctly from them, you can now make use of the search query and the list of item metadata in order to render a filtered list based on the query.

note

When working with HTML <input> tags, you can specify the type property to be of 'number' if the input field corresponds to a numerical input.

Part 3 - Render the Grocery List#

Create a new component called GroceryList.tsx. This should display the list in a similar way as the songs list from Assignment 4, but should be made up of the items that have the search query as a substring of their name (hint). It should also show each item's name and price. You can format it as in the GIF.

Part 4 - Conditional Rendering#

Use conditional rendering to handle two cases: first, if there are no grocery items in the list, render some text that tells the user that the list is empty. Otherwise, don't display anything. Second, if the search query didn't match any of the items in the list, make sure to render a message saying that the item could not be found.

Part 5 (Optional): Input Validation#

You can perform input validation on the onClick event of our add item button by making sure that the name is not the empty string and the price is positive. This is seen in the demo, and implemented using an alert() function call to alert the user. (Note: generally, we avoid using alert() in actual production-level apps, since it can be annoying and look like spam. If this were a more professional app, we would use some notification UI such as toasts.)

Submission#

Submit to CMS a zip file of everything in your project (create-react-app) directory but remove node_modules . Failure to remove node_modules will result in a 10 point deduction.

FAQ#

Does my app need to look exactly like what the GIF shows?#

No, you're free to make your UI as pretty or as ugly as you want, as long as the functionality is there.

How do I get the type for the callback function when lifting the state up from the child components?#

You can mouse over the type (using VS Code) of the setter function in the useState hook for the state you want to lift up into the App.tsx. This way, you can use it in the prop type for each of the child components that need it.

Getting a weird error with my items state in the App.tsx (never[])#

Unfortunately, TypeScript can't infer the type of your state if you set the initial value to simply [], and it assumes that it's just a falsy value. To fix this, make sure to parametrize the useState hook using the type definition you created; for example, const [state, setState] = useState<myType[]>([]).