this.state 工作时无法从 useState 获取值

Can't get value from useState when this.state works

我正在尝试使用来自 firebase 数据库的数据创建待办事项列表。在下面的代码中,它运行一个名为 handleChange 的函数,该函数在用户选中或取消选中某个框时运行。根据它是否被选中以及复选框的 ID,它会在单击时从 true 或 false 翻转。我尝试在 REACT 和 Google Firebase 中复制这个 tutorial 但没有成功。

    const [allTodos, setTodos] = useState([])  
    useEffect(() => {
        const database = firebase.database().ref();
        database.on("value", logData)  
    }, []) 

    function logData(rowData) {    
        setTodos(rowData.val())
    } 
    function handleChange(id) {
        console.log(id);
        setTodos(prevState => {
            const updatedTodos = prevState.allTodos.map(todo => {
                if (todo.id === id) {
                    todo.completed = !todo.completed
                }
                return todo
            })
            return {
                allTodos: updatedTodos
            }

        })   
    }

出现此错误:TypeError: Cannot read property 'map' of undefined

  17 | function handleChange(id) {
  18 |     console.log(id);
  19 |     setTodos(prevState => {
> 20 |         const updatedTodos = prevState.allTodos.map(todo => {
     | ^  21 |             if (todo.id === id) {
  22 |                 todo.completed = !todo.completed
  23 |             }

从代码中不确定状态发生了什么以及何时调用更改处理程序,但可以肯定的是状态在 handle change 时没有任何 allTodos,最好更新state 与 prevState 无关。让我们将状态更新分开如下,看看会发生什么

const updatedTodos = allTodos.map(todo => {
                if (todo.id === id) {
                    todo.completed = !todo.completed
                }
            });
 setTodos(updatedTodos);

prevState.allTodos 未定义,因为 prevState 不是具有 allTodos 属性 的对象... prevState 本身是 allTodos

试试这个:

    const [allTodos, setTodos] = useState([])  
    useEffect(() => {
        const database = firebase.database().ref();
        database.on("value", logData)  
    }, []) 

    function logData(rowData) {    
        setTodos(rowData.val())
    } 
    function handleChange(id) {
        console.log(id);
        setTodos(prevTodos => {
            const updatedTodos = prevTodos.map(todo => {
                if (todo.id === id) {
                    todo.completed = !todo.completed
                }
                return todo
            })
            return updatedTodos // <-- return the todos, not an object
        })   
    }