React Hooks产生奇怪的“ id”和复选框行为

时间:2019-12-03 20:49:55

标签: javascript reactjs react-hooks

我正在使用React Hooks构建一个简单的“待办事项列表”。现在我有两个问题:

1)前两个列表项具有相同的“ id”值(即使我增加了计数器...) enter image description here

2)仅在双击后选中并更新复选框

我将很感谢您的提示,线索,评论,建议和解决方案! :-)

这是“ ToDoList”组件:

import React, { useState, useEffect } from 'react';
import ListItem from './ToDoItem';

const ToDoList = () => {
let [counter, setCounter] = useState(1);
let initialItem = {
    id: counter,
    name: '',
    time: '',
    finished: false,
}

const [tasks, setTasks] = useState([]);
useEffect(() => console.log('THE ARRAY OF TASKS', tasks), [tasks]);

const [task, setTask] = useState(initialItem);

const handleSubmit = (e) => {
    e.preventDefault();
    setCounter(counter + 1);
    setTask(prevState => {
        return { ...prevState, id: counter}
    });
    setTasks([...tasks, task]);
    setTask(initialItem);
}

const deleteItem = (id) => {
    let newTasks = tasks.filter((item, index) => {
        return index !== id
    });
    setTasks(newTasks);
}

const handleCheckbox = (val, id) => {
    tasks.map((element) => {
        if (element.id === id) {
            element.finished = val
        }
    })
    console.log('UPDATED TASKS', tasks)
}

return (
    <div>
        <form onSubmit={handleSubmit}>
            <input placeholder="Add a task" value={task.name} onChange={(e) => {
                let value = e.target.value;
                setTask(prevState => {
                    return { ...prevState, name: value }
                })
            }}></input>

            <input placeholder="Add time" value={task.time} onChange={(e) => {
                let value = e.target.value;
                setTask(prevState => {
                    return { ...prevState, time: value }
                })
            }}></input>
            <button>Submit</button>
        </form>
        <ListItem tasks={tasks} delete={deleteItem} checked={handleCheckbox} />
    </div>
)
}

export default ToDoList;

这是“ ListItem”组件:

import React, { useState } from 'react';


function ListItem(props) {
    const tasks = props.tasks;
    const [isChecked, setIsChecked] = useState(false);

    return tasks.map((element, index) => {
        return <li key={index}>
            {element.name}: {element.time}
            <button onClick={() => props.delete(index)}>delete</button>
            <label className="container">
                <input type="checkbox" checked={element.finished}
                    onChange={(e) => setIsChecked(!isChecked)} 
                    onClick={(e) => {props.checked(isChecked, element.id);}}>
                </input>
                <span className="checkmark"></span>
            </label>
        </li>
    })
}

export default ListItem;

1 个答案:

答案 0 :(得分:1)

状态设置器是异步的,这意味着setCounter之后的行可能会在计数器值实际更新之前运行。

在您的情况下,似乎唯一一次更新计数器是在添加新任务之前,因此您可以重构代码,以便当计数器更改时,任务的添加就会生效:

const handleSubmit = (e) => {
    e.preventDefault();
    setCounter(count => count + 1);
};
useEffect(() => {
    setTask(prevState => {
        return { ...prevState, id: counter}
    });
    setTasks([...tasks, task]);
    setTask(initialItem);
}, [counter]);

尽管现在,在setTask尚未完成时,使用task可能会遇到相同的问题。但是,您可能不需要设置任务,使用任务然后再将任务重置为这种状态。尝试以下方法:

const handleSubmit = (e) => {
    e.preventDefault();
    setCounter(count => count + 1);
};
useEffect(() => {
    const newTask = {...task, id: counter};
    setTasks([...tasks, task]);
    setTask(initialItem);
}, [counter]);

这样,无需任何代码就可以等待任务状态更新,也不会出现竞争条件。 (这假设“任务”在提交之前不可能立即更改,因此在创建新对象时只需拉出“任务”的当前值即可。)