Well, the project that will be presented is very simple, but served to consolidate basic knowledge about React, I chose to use typescript, because the code becomes more readable and simple, but if you prefer you can use normal javascript.
The project will use:
- Typescript
- React Hooks
- Material UI
1-Step:
Create the project with create-react-app TodoList using or not the Typescript template.
npx create-react-app TodoList --template typescript
# or
yarn create react-app TodoList --template typescript
2-Step:
With the project created, install Material ui.
# using npm
npm install @material-ui/core
# using yarn
yarn add @material-ui/core
Also add the icon pack:
# using npm
npm install @material-ui/icons
# using yarn
yarn add @material-ui/icons
3-Step:
Create a file TodoList.tsx
where all the project code will be, also create a styles folder containing TodoList.css
if you want to style the project.
4-Step:
In TodoList.tsx
import the hook useState, TextField, ButtonIcons, AddIcon and DeleteIcon from the ui material.
import React, { useState } from 'react';
import { TextField, IconButton } from '@material-ui/core';
import AddIcon from '@material-ui/icons/Add';
import DeleteIcon from '@material-ui/icons/Delete';
Next we will create an interface
, interface in typescript is the way to name types, so we will create our TodoItem interface passing the value of id as number and value as a string.
interface TodoItem {
id: number
value: string
}
Create a state useState set
and setList
with an array of type TodoItem
, in its default value we will pass an array with id: 0
, and the empty string value: ''
. Then we'll create functions of type handleChange
, handleAdd
and handleDelete
to handle this list :
export const TodoList: React.FC = () => {
const [list, setList] = useState<TodoItem[]>([{ id: 0, value: '' }])
const handleChange = (value: string, id: TodoItem['id']) => {
setList(prev => prev.map(item => item.id === id ? { ...item, value } : item ))
}
const handleDelete = (id: TodoItem['id']) => {
setList(prev => prev.filter(item => item.id !== id))
}
const handleAdd = (index: number) => {
const newItem = { id: count ++, value: '' }
setList(prev => [...prev.slice(0, index + 1), newItem, ...prev.slice(index + 1)])
}
5-Step:
In the return
pass a list.map
taking the item
and the index
, rendering a div
,where we will pass a key
with value item.id
which will be unique to each item, then we will also render the TextField
from the ui material with a value
and the onChange
. Then we pass the IconButton
also from the material ui rendering the IconAdd
with an onClick
and we do the same thing with the IconDelete
but passing the handleDelete
instead of the handleAdd
.
return (
<div>
{list.map((item, index) => (
<div key={item.id}>
<TextField
value={item.value}
onChange={e => handleChange(e.currentTarget.value, item.id)}
/>
<IconButton onClick={() => handleAdd(index)}>
<AddIcon />
</IconButton>
{list.length > 1 && (
<IconButton onClick={() => handleDelete(item.id)}>
<DeleteIcon />
</IconButton>
)}
</div>
))}
</div>
Note.1: the list.length
is the quantity of the list,in other words, it will always start with 1 item.
Note.2: We will also create a variable let count = 1
to simulate an id.
Result
The TodoList.tsx
will look like this:
import React, { useState } from 'react';
import { TextField, IconButton } from '@material-ui/core';
import AddIcon from '@material-ui/icons/Add';
import DeleteIcon from '@material-ui/icons/Delete';
interface TodoItem {
id: number
value: string
}
let count = 1
export const TodoList: React.FC = () => {
const [list, setList] = useState<TodoItem[]>([{ id: 0, value: '' }])
const handleChange = (value: string, id: TodoItem['id']) => {
setList(prev => prev.map(item => item.id === id ? { ...item, value } : item ))
}
const handleDelete = (id: TodoItem['id']) => {
setList(prev => prev.filter(item => item.id !== id))
}
const handleAdd = (index: number) => {
const newItem = { id: count ++, value: '' }
setList(prev => [...prev.slice(0, index + 1), newItem, ...prev.slice(index + 1)])
}
return (
<div>
{list.map((item, index) => (
<div key={item.id}>
<TextField
value={item.value}
onChange={e => handleChange(e.currentTarget.value, item.id)}
/>
<IconButton onClick={() => handleAdd(index)}>
<AddIcon />
</IconButton>
{list.length > 1 && (
<IconButton onClick={() => handleDelete(item.id)}>
<DeleteIcon />
</IconButton>
)}
</div>
))}
</div>
)
}
the project link :
Top comments (2)
Thanks for sharing, Beatriz!
Very well !!