React hooks [] practices regarding useCallback bring closure issue

Problem Description

// 举个栗子,我用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

Said write a simple pseudo-code function, that is, substantially, the button click button1, SearchId added to the value 1, sends a request click button2.
Began to describe the problem: When we click four times button1, to change the value of searchID to 4, then click button2, will find that the request is sent, the value searhID is 0.

problem analysis

Why would such a problem? Because we use a callback method onSearchInfos useCallback request data package layer, and the second parameter we pass a [], it indicates that only when the component is first created, the callback function is created, so as to improve performance!

Under review, I mentioned above when it comes to what?

OnSearchInfos only be created when the first components created! the first time!
That searchID get value when first created, the value passed to form a closure.

Solution 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

Solution 2

Solution 3

As far as I know, there are at least two solutions, big brother next door and just finished discussing, have not had time to study, to look at the weekend, follow-perfect!

Guess you like

Origin www.cnblogs.com/fe-linjin/p/11402288.html