• 【React hooks】关于useCallback带来的闭包问题实践方案


    问题描述

    // 举个栗子,我用hooks 写了这么一个组件
    let Test = () => {
        /** Search base infos */
        const [searchID, setSearchID] = useState(0)
    
        /** Search info action */
        const onSearchInfos = useCallback(() => {
            let fetchUrl = '/api/getSearchInfos'
            let fetchParams = { searchID }
            fetch(fetchUrl, {
                method: 'POST',
                body: JSON.stringify(fetchParams)
            }).then(res => res.json()
            ).then(res => {
               console.log(res)
            })
        }, [])
    
        return (
            <>
                <button onClick={() => {setSearchID(searchID + 1)}} >button1</button>
                <button onClick={() => {onSearchInfos()}}>button2</button>
            </>
        )
    }
    
    export default Test
    

    上述写了一个很简单的伪代码功能,大致就是,点击button1按钮,searchID的值加1,点击button2发送一个请求。
    开始描述问题:当我们点击了四次button1,把searchID的值更改到了4,然后点击button2,会发现,发送出去的请求,searhID的值是0。

    问题分析

    为什么会产生这种问题呢?因为我们使用useCallback将请求数据的回调方法onSearchInfos包裹了一层,并且第二参数我们传递了一个[],表示只在组件第一次创建的时候,这个回调函数被创建,从而去提升性能!

    回顾下, 我上面说到了什么?

    只在第一次组件创建的时候onSearchInfos被创建!第一次!
    也就是说searchID拿到的值是第一次被创建的时候,传入的值,形成了一个闭包。

    解决方案1

    interface IRef {
        current: any
    }
    
    let Test = () => {
        /** Search base infos */
        const [searchID, setSearchID] = useState(0)
    
        /** 解决闭包问题 */
        const fetchRef: IRef = useRef() // hooks为我们提供的一个通用容器,里面有一个current属性
        fetchRef.current = { //  为current这个属性添加一个searchID,每当searchID状态变更的时候,Test都会进行重新渲染,从而current能拿到最新的值
            searchID
        }
    
        /** Search info action */
        const onSearchInfos = useCallback(() => {
            let fetchUrl = '/api/getSearchInfos'
            let fetchParams = { ...fetchRef.current } // 解构参数,这里拿到的是外层fetchRef的引用
            fetch(fetchUrl, {
                method: 'POST',
                body: JSON.stringify(fetchParams)
            }).then(res => res.json()
            ).then(res => {
               console.log(res)
            })
        }, [])
    
        return (
            <>
                <button onClick={() => {setSearchID(searchID + 1)}} >button1</button>
                <button onClick={() => {onSearchInfos()}}>button2</button>
            </>
        )
    }
    
    export default Test
    

    解决方案2

    点击查看另外一篇文章

    解决方案3

    据我所知,目前至少还有两种解决方案,刚和隔壁大佬讨论完,还没来得及研究,周末研究一下,后续完善!

  • 相关阅读:
    chrome 浏览器与chromedriver 对应关系以及 对应的驱动下载
    pip 安装six 报错 ModuleNotFoundError: No module named 'pip._internal.cli.main'
    django 连接远程mysql 报错 django.db.utils.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: NO)")
    MySQL8.0允许外部访问
    Linux 安装mysql
    php导出导入excel插件
    解决php导出csv文件utf8中文乱码问题
    Docker 安装mysql5.6
    centos7 设置静态IP
    U盘制作centos7系统并安装
  • 原文地址:https://www.cnblogs.com/fe-linjin/p/11402288.html
Copyright © 2020-2023  润新知