我想做一个带有钩子的待办事项清单。这是我的相关代码。
function generateId() {
return '_' + Math.random().toString(36).substr(2, 9);
};
export function TodoList(){
const [todos, setTodos] = React.useState([])
const [input, setInput] = React.useState('')
const [time, setTime] = React.useState('')
const handleSubmit = () => {
setTodos((todos) => todos.concat({
text: input,
id: generateId(),
timeRequired: time,
}))
setInput('')
setTime('')
}
// remove to do works fine.
const removeTodo = (id) => setTodos((todos) => todos.filter((todo) => todo.id !== id ))
/// confusion here
let todo = (id) => todos.find(x => x.id = id)
const decrement = (id) => setTodos((todo(id).timeRequired) => timeRequired - 1)
///
return(
<React.Fragment>
<input type="text" value={input} placeholder="New Task" onChange={(e) => setInput(e.target.value)}>
</input>
<input type="number" value={time} placeholder="Hours Required" onChange={(e) => setTime(e.target.value)}>
</input>
<button onClick={handleSubmit}> Submit </button>
<ul>
{todos.map(({text, id, timeRequired}) => (
<li key={id}>
<span>{text}: remaining {timeRequired} hours </span>
<button onClick={() => removeTodo(id)}>
Cancel ❌
</button>
<button onClick={() => decrement(id)}> Decrement ➖ </button>
<button > Increase ➕ </button>
<button> Done ✔️ </button>
</li>
))}
</ul>
</React.Fragment>
)
}
所以我想增加/减少待办事项列表上剩余的时间。但是,我不知道如何选择列表中的特定项目并更改一个属性(剩余时间)并保留text属性。
谢谢。
答案 0 :(得分:2)
这是decrement
函数的外观。这将占用id
,并在所有todos
上循环。如果todo
与提供的id
不匹配,请保持原样。如果匹配,则创建对象的浅表副本({...todo}
),并使用更新后的值覆盖timeRequired
属性。
const decrement = (id) => setTodos((todos) => todos.map((todo) => {
if (todo.id != id) return todo;
return {...todo, timeRequired: todo.timeRequired - 1};
}));
请注意,{...todo, timeRequired: todo.timeRequired - 1}
的顺序很重要。通过将timeRequired: todo.timeRequired - 1
放在...todo
之后,它将覆盖现有属性。就像对象{a: 1, b: 2, a: 3}
将使您拥有对象{a: 3, b: 2}
一样,因为键a
的第二个定义将覆盖第一个。
答案 1 :(得分:1)
一旦您确定了数组中的元素,就从待办事项中使用递减的timeRequired
属性创建一个新对象。然后使用.slice
在新项目前后对数组进行切片,并将新项目置于中间:
const decrement = (i) => {
const replacedTodo = {
...todos[i],
timeRequired: todos[i].timeRequired - 1,
};
setTodos(
todos.slice(0, i),
replacedTodo,
todos.slice(i + 1),
);
};
{todos.map(({ text, id, timeRequired }, i) => (
// ...
<button onClick={() => decrement(i)}> Decrement ➖ </button>
直接使用.map
函数中的索引要比以后从ID中找到匹配的元素容易。
答案 2 :(得分:1)
您可以这样尝试
const decrement = (id) => {
const targetTodo = todos.find(x => x.id == id); //get the todo
const currentTime = targetTodo.timeRequired -1 //decrease the time
const newTodo = { ...targetTodo , timeRequired : currentTime } // create new todo object
const newTodoList = todos.map( item => { // finally replace the old todo object
if(item.id = id) return newTodo
else return item;
})
setTodos(newTodoList)
}
答案 3 :(得分:1)
尝试一下...
const removeTodo = (id) => setTodos((todos) => todos.filter((todo) => todo.id !== id ))
const decrement = (id) => setTodos((todos) => todos.map((todo) => {
const {
id: oldID,
timeRequired,
} = todo;
return {
...todo,
timeRequired: id===oldID? timeRequired-1 : timeRequired,
};
}));