I'm making a todo list in react js. Each time a new todo item is created, some buttons are appended next to it along with a edit input text box. I'm trying to avoid using refs but purely usestate for my case, however I can't figure out how to do it. At its current state, all edit text inputs are using the same state and that brings focus loss along with other issues. I'd highly appreciate any suggetsions.
import "./theme.css"
import * as appStyles from "./styles/App.module.css"
import * as todoStyles from "./styles/Todo.module.css"
import { useState } from "react"
const initialState = [
{
id: "1",
name: "My first ToDo",
status: "new",
},
]
export function App() {
const [numofItems, setNumofItems] = useState(2)
const [newToDo, setnewToDo] = useState('');
const [todos, setTodos] = useState(initialState);
const [editTodo, setEditTodo] = useState({name: ""});
const onAddTodo = () => {
setnewToDo("");
setTodos((old) => [
...old,
{ id: numofItems.toString(), name: newToDo, status: "new" },
])
setNumofItems(numofItems + 1);
}
deleteList = () =>{
setTodos([]);
}
const handleEdit = (id, description) =>{
let el = todos.map((item) => {if(item.id === id) {item.name = description} return item});
setTodos(el);
setEditTodo('');
}
const handleMove = (id, position) =>{
const search = obj => obj.id === id;
const todoIndex = todos.findIndex(search);
if(position === "up"){
if (todos[todoIndex - 1] === undefined) {
} else {
const newTodo1 = [...todos];
const temp1 = newTodo1[todoIndex - 1];
const temp2 = newTodo1[todoIndex]
newTodo1.splice(todoIndex - 1, 1, temp2);
newTodo1.splice(todoIndex, 1, temp1);
setTodos([...newTodo1]);
}
}
else if(position === "down"){
if (todos[todoIndex + 1] === undefined) {
} else {
const newTodo1 = [...todos];
const temp1 = newTodo1[todoIndex + 1];
const temp2 = newTodo1[todoIndex]
newTodo1.splice(todoIndex + 1, 1, temp2);
newTodo1.splice(todoIndex, 1, temp1);
setTodos([...newTodo1]);
}
}
}
const Todo = ({ record }) => {
return <li className={todoStyles.item}>{record.name}
<button className={appStyles.editButtons} onClick={() => deleteListItem(record.id)} >Delete</button>
<button className={appStyles.editButtons} onClick={() => handleEdit(record.id, editTodo.name)}>Edit</button>
<button className={appStyles.editButtons} onClick={() => handleMove(record.id, "down")}>Move down</button>
<button className={appStyles.editButtons} onClick={() => handleMove(record.id, "up")}>Move up</button>
<input className={appStyles.input}
type = "text"
name={`editTodo_${record.id}`}
value = {editTodo.name}
onChange={event => {event.persist();
setEditTodo({name: event.target.value});}}
/></li>
}
const deleteListItem = (todoid) => {
setTodos(todos.filter(({id}) => id !== todoid))
}
return (
<>
<h3 className={appStyles.title}>React ToDo App</h3>
<ul className={appStyles.list}>
{todos.map((t, idx) => (
<Todo key={`todo_${idx}`} record={t} />
))}
</ul>
<div className={appStyles.actions}>
<form>
<label>
Enter new item:
<input className={appStyles.input} type="text" name="newToDo" value={newToDo} onChange={event => setnewToDo(event.target.value)}/>
</label>
</form>
<button
className={appStyles.button}
onClick={onAddTodo}
>
Add
</button>
<br></br>
<button className={appStyles.button} onClick={this.deleteList}>
Delete List
</button>
</div>
</>
)
}