Objective
Description
Suppose we have a list of items, each denoting a task to do, with a button next to it, as follows:
- Learn JavaScript
- Read story book
- Watch documentary
- Bake cupcakes
The button, which reads 'Done', serves to strikethrough the text of the corresponding item and then hide itself. In other words, it serves to signal that a particular task is done.
This list of items has some similarities to a typical to-do list but it isn't exactly like one. For example, there is no input field to add more items, nor is there any way to remove a task.
In this exercise, your task is to implement this program using React.
The list should be denoted via a separate component (you can name it whatever you want to but the name should obviously be meaningful), and even a list item should be denoted via a separate component.
The component representing the list should take in an items
prop which is an array containing all the items to be added to the list; each item is a string.
Here are a couple further points to note when a button is clicked:
- The strikethrough effect should be given using the
<s>
HTML element, not using any CSS styles. - The button should be hidden by removing it from the DOM, not by merely hiding it using some CSS (such as by using
display: none
).
In the end, the you should get the following program:
New file
Inside the directory you created for this course on React, create a new folder called Exercise-6-That's-Done and put the .js solution files for this exercise within it.
Solution
Let's start by reviewing what exactly do we need to create for this exercises and then get to actually creating it.
We need to create a component that renders a <ul>
list, wherein the items are obtained via an items
prop. Each list item is denoted as a separate component as well, obviously rendering an <li>
element, containing the text of the item and a 'Done' button.
When clicked, the button serves to strikethrough the corresponding item and remove itself.
And that's it.
Now let's start coding this program, starting with perhaps the most difficult thing in programming — naming.
We could name the main component that represents the list as List
, ItemList
, CancellableItemList
(to convey more meaning in the name), InteractiveItemList
(not very cool), and so on.
Items
because there is a high chance of typos happening when writing it out. That is, Items
could be mistakenly typed as Item
.I particularly like the name CancellableItemList
and would use that. In this respect then, each item of the list could be called CancellableItem
. Simple.
Now, let's implement both these components.
CancellableItemList
takes in an items
prop and renders a <ul>
element with a list of CancellableItem
elements.
So let's first code this:
function CancellableItemList({ items }) {
return (
<ul>
{items.map((item, i) => (
<CancellableItem key={i} item={item} />
))}
</ul>
);
}
Recall from the previous chapter, React Rendering Lists, that when rendering a list of elements, the key
prop is required on each element, with a unique value in that list. When we're not much concerned with real uniqueness, the index of each element of an array is sufficient to be used as key
and that's exactly what we do above.
Now, let's move over to CancellableItem
.
Each item
of the items
list in CancellableItemList
is provided to CancellableItem
in the form of an item
prop. A CancellableItem
denotes an <li>
element containing a given piece of text, followed by a 'Done' button.
First, let's get this done and then refine the code to meet our needs:
function CancellableItem({ item }) {
return (
<li>{item} <button>Done</button></li>
);
}
Currently, CancellableItem
doesn't maintain any state but from the description above, we know that it needs to. That's simply because either the underlying item is cancelled (or striken-through) or not cancelled. The item can be in either of two states.
Let's call this state value cancelled
. Initially, it's false
. The button serves to change this state to true
.
When cancelled
is true
, the item's text ought to be shown wrapped up inside an <s>
element. Recall what this means? Well, it means conditional rendering.
Both the text and the button need to be conditionally rendered:
- Either the text is shown directly or is wrapped up inside an
<s>
element, depending on the value ofcancelled
. - Either the button is rendered or not rendered, again depending on the value of
cancelled
.
The following code accomplishes this all:
import React, { useState } from 'react';
function CancellableItem({ item }) {
const [cancelled, setCancelled] = useState(false);
return (
<li>
{cancelled ? <s>{item}</s> : item}
{!cancelled && <button onClick={() => setCancelled(true)}>Done</button>}
</li>
);
}
That's essentially it.
Let's now test this program using a dummy array provided to the items
prop of CancellableItemList
:
import CancellableItemList from './CancellableItemList';
function App() {
return (
<CancellableItemList items={[
'Learn JavaScript',
'Read story book',
'Watch documentary',
'Bake cupcakes',
]}/>
);
}
Voila! There we have it.
And this completes this exercise.