求助大佬, React 严格模式+函数式`setState`导致 key 重复

查看 77|回复 4
作者:dcsuibian   
我有一个列表,我希望每次 ajax 请求获取一页数据后,将新的一页数据追加到列表当中。
在组件挂载时,我希望读取第一页的内容。简化后的代码可以写成这样:
import {useEffect, useState} from "react";
interface User {
    id: number
    name: string
}
const pageData = [
    {id: 1, name: '张三'},
]
export default function App() {
    const [users, setUsers] = useState[U]([])
    const fetchUsers = async () => {
        const page = pageData // 异步获取到数据
        setUsers([...users, ...page])
    }
    useEffect(() => {
        fetchUsers() // 发送异步请求
    }, [])
    // 渲染列表
    return (
        
            {users.map(user => (
                {user.name}
            ))}
        

    )
}
这样不会有任何问题。
但是今天我问 ChatGPT 的时候,他给了我这么个回答。

我觉得有点道理。所以我就在想,我是往列表里追加数据,那肯定是依赖于前一个状态的。因此我就把代码从
setUsers([...users, ...page])
改成了
setUsers(prevUsers=>[...prevUsers, ...page])
完整代码 :
import {useEffect, useState} from "react";
interface User {
    id: number
    name: string
}
const pageData = [
    {id: 1, name: '张三'},
]
export default function App() {
    const [users, setUsers] = useState[U]([])
    const fetchUsers = async () => {
        const page = pageData // 异步获取到数据
        setUsers(prevUsers=>[...prevUsers, ...page])
    }
    useEffect(() => {
        fetchUsers() // 发送异步请求
    }, [])
    // 渲染列表
    return (
        
            {users.map(user => (
                {user.name}
            ))}
        

    )
}
但这时候就出现了报错:

列表的数据追加了两次,key 也重复了。
我立马想到 React 的严格模式,果然关闭了,就又正常了:

到目前为止,我确实可以简单地
[ol]
  • 把 useState 改回去
  • 关闭严格模式
    [/ol]
    以解决这个问题。
    但是我觉得使用函数式的 setState 其实并没有太大问题,而 React 的严格模式又是官方推荐的。这俩者结合到一起,咋就出问题了呢?望大佬指点,是不是我使用的方式有问题。

    React, const, setusers, user

  • qscasdqwezxc   
    useeffect 会 call 两次在 strict mode
    防止你有泄露的资源每有清理
    你初始化的时候应该先检查有没有初始化过
    如果已经初始化过了就不用再初始化了
    7immy   
    https://zh-hans.react.dev/learn/you-might-not-need-an-effect
    7immy   
    同 1L ,判断初始化,还有我感觉用不到 effect
    Leviathann   
    自己写一个 useMounted(action)
    用 ref 记录是否是初次渲染,在 useEffec 里根据 ref 判断要不要执行传入的 action
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部