Skip to Content
Courses

Possible Improvements

There are 2 things we can improve in our current solution.

First, to make things more readable and rescalable, it would be good if we extract list item implementation from List component in a completely new component called ListItem.tsx and we can use it inside our List component and pass props that are needed to render everything properly.

import { Todo } from "../store/reducers/todo"; interface ListItemInterface { item: Todo; removeItemFromList: Function; toggleItemDone: Function; } function ListItem(props: ListItemInterface) { return ( <li className="flex items-center p-2"> <input onChange={() => props.toggleItemDone(props.item.id)} type="checkbox" className="h-4 w-4 mr-2 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded" checked={props.item.is_done} /> <p className={ "w-full" + (props.item.is_done ? " line-through" : "") } > {props.item.title} </p> <button onClick={() => props.removeItemFromList(props.item.id)} type="button" className="w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-2 py-0.5 bg-white text-base font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-1 focus:ring-offset-2 focus:ring-red-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" > Remove </button> </li> ); } export default ListItem;

When we created our ListItem component and extracted logic from List component, we need to update our List component to use ListItem component.

import { Todo } from "../store/reducers/todo"; import ListItem from "./ListItem"; interface ListInterface { list: Todo[]; removeItemFromList: Function; toggleItemDone: Function; } function List(props: ListInterface) { return ( <ul className="p-8 pt-0 divide-y"> {props.list.length > 0 && props.list.map((todo_item: Todo) => ( <ListItem key={todo_item.id} item={todo_item} removeItemFromList={props.removeItemFromList} toggleItemDone={props.toggleItemDone} /> ))} {props.list.length < 1 && ( <p>Your todo list is empty, please add some todo.</p> )} </ul> ); } export default List;

At the end, everything should look and work the same, but we just want to make our code more readable and scalable.


One more thing that we can do a bit better is to remove input value whenever we add an item, so after adding an item input field gets cleared.

import { useDispatch, useSelector } from "react-redux"; import ListHeader from "../components/ListHeader"; import List from "../components/List"; import { addItem, markItemAsDone, removeItem } from "../store/actions/todo"; import { useState } from "react"; import { RootState } from "../store/reducers"; function TodoList() { const dispatch = useDispatch(); const [title, setTitle] = useState<string>(""); const todo: any = useSelector((state: RootState) => state.todo); const addItemToList = () => { if (!title) return; dispatch(addItem(title)); setTitle(''); }; const removeItemFromList = (item_id: number) => { dispatch(removeItem(item_id)); }; const toggleItemDone = (item_id: number) => { dispatch(markItemAsDone(item_id)); }; return ( <div className="flex justify-center items-center h-screen"> <div className="shadow-lg rounded-lg w-[500px]"> <ListHeader addItemToList={addItemToList} title={title} setTitle={setTitle} /> <List list={todo.todo_list} removeItemFromList={removeItemFromList} toggleItemDone={toggleItemDone} /> </div> </div> ); } export default TodoList;
Last updated on