【问题标题】:Can't get value from useState when this.state worksthis.state 工作时无法从 useState 获取价值
【发布时间】:2020-08-18 07:51:51
【问题描述】:

我正在尝试使用来自 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 |             }

【问题讨论】:

    标签: reactjs firebase-realtime-database use-effect react-functional-component use-state


    【解决方案1】:

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

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

    【讨论】:

    • 有趣,如果我想记住以前的状态怎么办?例如,如果我有一个函数可以在单击按钮时将变量增加 +1。
    • 同样的方法,你的状态包含一些东西,让我们先说0然后addByOne处理程序被调用,所以你要做的是0+1,所以你不需要解构0 as prevState,因为你当前的状态是0,所以基本上setState(state+1);
    【解决方案2】:

    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
            })   
        }
    

    【讨论】:

    • 您的解决方案返回updatedTodos,但未设置allTodos = updatedTodos
    • 请注意,我正在使用setTodos 的功能版本。从该函数返回的值被设置为新的allTodos 值。有关功能性useState 的文档,请参见此处:reactjs.org/docs/hooks-reference.html#functional-updates
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    • 2017-09-07
    • 1970-01-01
    相关资源
    最近更新 更多