todo list using react
When i changed jobs for the second time, the interviewer asked me to create a todo list using react. I think it's a good question to test the candidate's ability to think and code. Not like stereotyped writing, it's more like a real interview question.
Let's start with the basic structure of the todo list.
First, we need a input field to add a new todo.
<input type="text" placeholder="new thing to be done" />
Second, we need a list to show all the todos.
const [todos, setTodos] = useState([])
then we need to render the list:
{
todos.map((todo) => <li key={todo.id}>{todo.text}</li>)
}
Now, let's put these components together.
const [todos, setTodos] = useState([])
return (
<div>
<input type="text" placeholder="new thing to be done" />
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</div>
)
Now, we need to handle the input field. We can use form to wrap the input field.
const inputRef = useRef(null)
<form onSubmit={handleSubmit}>
<input type="text" placeholder="new thing to be done" ref={inputRef} />
</form
Why we need to use form? Because we want to prevent the page from refreshing when we enter a new todo. For sure, you can also choose other ways to handle this.
const handleSubmit = (e) => {
e.preventDefault()
setTodos([...todos, { id: Date.now(), label: inputRef.current.value }])
inputRef.current.value = ""
}
Let's put these components together.
function TodoList() {
const inputRef = useRef(null)
const [todos, setTodos] = useState([])
const handleSubmit = (e) => {
e.preventDefault()
setTodos([...todos, { id: Date.now(), label: inputRef.current.value }])
inputRef.current.value = ""
}
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" placeholder="new thing to be done" ref={inputRef} />
</form>
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.label}</li>
))}
</ul>
</div>
)
}
Now we can add a new todo. But we need to toggle the todo when it's done or not. We should add a checkbox to the todo. And add a line-through style if it's checked.
const handleToggle = (id) => {
setTodos(
todos.map((todo) => (todo.id === id ? { ...todo, done: !todo.done } : todo))
)
}
<li key={todo.id}>
<input
type="checkbox"
checked={todo.done}
onChange={() => handleToggle(todo.id)}
/>
<label className={item.done ? "done" : "undo"}>{todo.label}</label>
</li>
After we also need to add a button to delete the todo.
<li key={todo.id}>
<input
type="checkbox"
checked={todo.done}
onChange={() => handleToggle(todo.id)}
/>
{todo.label}
<button onClick={() => handleDelete(todo.id)}>x</button>
</li>
const handleDelete = (id) => {
setTodos(todos.filter((todo) => todo.id !== id))
}
That's it. We have a todo list.
function TodoList() {
const inputRef = useRef(null)
const [todos, setTodos] = useState([])
const handleSubmit = (e) => {
e.preventDefault()
setTodos([
...todos,
{ id: Date.now(), label: inputRef.current.value, done: false },
])
inputRef.current.value = ""
}
const handleDelete = (id) => {
setTodos(todos.filter((todo) => todo.id !== id))
}
const handleToggle = (id) => {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, done: !todo.done } : todo
)
)
}
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" placeholder="new thing to be done" ref={inputRef} />
</form>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.done}
onChange={() => handleToggle(todo.id)}
/>
<label className={item.done ? "done" : "undo"}>{todo.label}</label>
<button onClick={() => handleDelete(todo.id)}>x</button>
</li>
))}
</ul>
</div>
)
}
If you can complete this above, i think your answer basically meets the requirements.
But we can do better, like:
- We can extract the todo list component to a separate component.
- We can make the todo list component more beautiful by using css.
- We can add a filter to the todo in case it's empty.
- We can use memo and useCallback to optimize the todo list component.
- We can use local storage to store the todo list.
- ...
If you can complete these above, i think your answer is excellent. Have a try, good luck!