You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React State已有值但调用deleteTag时显示为空数组问题

React组件中deleteTag函数获取tags为空数组的问题解决

问题场景

组件通过useEffect成功获取标签数据并更新tags状态,但子组件调用deleteTag时,打印的tags却是初始的空数组。

代码复现

const CourseTags = () => {
    const [tags, setTags] = useState([])

    useEffect(() => {
        const jwt = sessionStorage.getItem("jwt")

        // GET tags
        fetch(`${process.env.NEXT_PUBLIC_HOST}/api/tags`, {
            method: "GET",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${jwt}`
            }
        })
            .then(res => res.json())
            .then(data => {
                setTags(data)
                console.log(data) // 正常显示标签数组 [ {}, {}, ... ]
            })
            .catch(err => {
                console.log(err)
            })
    }, [])


    const deleteTag = (tagId) => {
        if (confirm("Delete Tag?")) {
            console.log(tags, tagId) // tags 为空数组 []
         }
    }


    return (
      <Fragment>
           <TagsList tagsList={tags} handleDeleteTag={(tagId) => deleteTag(tagId)} />
      </Fragment>
)
}

问题原因

这是闭包陷阱导致的:

  • deleteTag函数在组件首次渲染时创建,它捕获了当时的tags状态(空数组)。
  • 后续useEffect获取数据更新tags后,组件会重新渲染并生成新的deleteTag函数,但如果子组件TagsList没有同步更新接收的handleDeleteTag回调(比如用了React.memo但未将该回调加入依赖项),或者因为confirm是异步操作,最终调用的还是首次渲染时的旧deleteTag,所以里面的tags始终是空数组。

解决方案

方案1:使用useRef保存最新的tags状态

用useRef跟踪最新的tags值,不管什么时候访问tagsRef.current,拿到的都是最新状态:

const CourseTags = () => {
    const [tags, setTags] = useState([])
    const tagsRef = useRef(tags)

    // 每次tags更新时同步更新ref
    useEffect(() => {
        tagsRef.current = tags
    }, [tags])

    useEffect(() => {
        const jwt = sessionStorage.getItem("jwt")
        fetch(`${process.env.NEXT_PUBLIC_HOST}/api/tags`, {
            method: "GET",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${jwt}`
            }
        })
            .then(res => res.json())
            .then(data => {
                setTags(data)
            })
            .catch(err => {
                console.log(err)
            })
    }, [])


    const deleteTag = (tagId) => {
        if (confirm("Delete Tag?")) {
            // 访问ref.current获取最新tags
            console.log(tagsRef.current, tagId)
         }
    }


    return (
      <Fragment>
           <TagsList tagsList={tags} handleDeleteTag={(tagId) => deleteTag(tagId)} />
      </Fragment>
)
}

方案2:用useCallback包裹deleteTag并添加依赖

通过useCallback确保deleteTag函数在tags变化时重新生成,同时如果子组件用了React.memo,要把handleDeleteTag加入依赖数组:

const CourseTags = () => {
    const [tags, setTags] = useState([])

    useEffect(() => {
        const jwt = sessionStorage.getItem("jwt")
        fetch(`${process.env.NEXT_PUBLIC_HOST}/api/tags`, {
            method: "GET",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${jwt}`
            }
        })
            .then(res => res.json())
            .then(data => {
                setTags(data)
            })
            .catch(err => {
                console.log(err)
            })
    }, [])

    // 用useCallback包裹,依赖tags
    const deleteTag = useCallback((tagId) => {
        if (confirm("Delete Tag?")) {
            console.log(tags, tagId)
         }
    }, [tags])


    return (
      <Fragment>
           <TagsList tagsList={tags} handleDeleteTag={deleteTag} />
      </Fragment>
)
}

如果TagsList是用React.memo包裹的子组件,需要确保它的props依赖正确:

const TagsList = React.memo(({ tagsList, handleDeleteTag }) => {
    // 子组件逻辑
}, (prevProps, nextProps) => {
    // 浅比较props,确保handleDeleteTag变化时重新渲染
    return prevProps.tagsList === nextProps.tagsList && prevProps.handleDeleteTag === nextProps.handleDeleteTag
})

方案3:直接在deleteTag中通过setTags的函数式更新获取最新状态(如果只是要更新tags)

如果你的目的是删除标签后更新状态,可以直接用函数式更新获取最新的tags,不需要在deleteTag里直接访问tags:

const deleteTag = (tagId) => {
    if (confirm("Delete Tag?")) {
        // 函数式更新,获取最新tags状态
        setTags(prevTags => prevTags.filter(tag => tag._id !== tagId))
     }
}

内容的提问来源于stack exchange,提问作者osomaher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 22:50:23