react-hook中setTimeout、useEffect执行顺序与数据矛盾

发布于 2022-09-11 21:48:29 字数 5194 浏览 9 评论 0

react-hook中setTimeout、useEffect执行顺序与数据矛盾

setTimeout、useEffect执行顺序

情况1:

const App = () => {
    const [count, setCount] = useState(0)
    const [total, setTotal] = useState(0)

    const sayVar = useCallback((tag = '') => {
        console.log('sayVar',tag,  count, total)
    }, [count, total])


    const reset = useCallback(() => {
        setCount(1)
        setTotal(1)//情况1:
        setTimeout(() => {
            console.log('setTimeout', count, total) //2 0 0
            sayVar('setTimeout') //3 0 0 
        }, 0)
        sayVar()// 1 0 0
    }, [count, total, sayVar])
    useEffect(() => {
        console.log('useEffect', count, total) //4 1 1
    }, [count, total])
    return (
        <div>
            <button onClick={reset}>reset</button>{count}{total}
        </div>
    )
}
执行结果顺序
1. sayVar  0 0
2. setTimeout 0 0
3. sayVar setTimeout 0 0
4. useEffect 1 1
结论:执行顺序setTimeout > useEffect

情况2:

const App = () => {
    const [count, setCount] = useState(0)
    const [total, setTotal] = useState(0)

    const sayVar = useCallback((tag = '') => {
        console.log('sayVar',tag,  count, total)
    }, [count, total])


    const reset = useCallback(() => {
        setCount(1)
        setTimeout(() => {
            setTotal(1)//情况2:
            console.log('setTimeout', count, total) //3 0 0
            sayVar('setTimeout') //4 0 0
        }, 0)
        sayVar() //1 0 0
    }, [count, total, sayVar])
    useEffect(() => {
        console.log('useEffect', count, total) //2 1 0 //5 1 1
    }, [count, total])
    return (
        <div>
            <button onClick={reset}>reset</button>{count}{total}
        </div>
    )
}
执行结果顺序
1. sayVar  0 0
2. useEffect 1 0
3. setTimeout 0 0
4. sayVar setTimeout 0 0
5. useEffect 1 1
结论:执行顺序setTimeout < useEffect 或者 setTimeout < useEffect
问题:为什么两端代码到处了一个很矛盾的结论: 执行顺序setTimeout < useEffect 或者 setTimeout < useEffect;这个结论该如何解释?

数据矛盾

情况:

需求:
    列表展示页:分两部分 1.上面过滤(tab,搜索)2.下面数据(表格,翻页器)
    tab、搜索、翻页器都能拿到对应的数据,点击搜索时将tab、翻页器重置为初始

const App = () => {
    const [type, setType] = useState(0)
    const [currentPage, setCurrentPage] = useState(0)
    const [searchValue, setSearchValue] = useState('')

    const doRequest = useCallback(() => {
        //接口设计如此
        api.post('/api/xxx', {
            type: type,
            currentPage: currentPage,
            searchValue: searchValue 
        }).then(res => { /*...*/ })
    }, [type, currentPage, searchValue])

    //切换类型
    const tabChange = useCallback((v) => {
        setTypev)
    }, [])
    useEffect(() => {
        doRequest()
    }, [type])

    // 为什么不用这种useEffect了?
    // useEffect(() => {
    //     doRequest()
    // }, [doRequest])

    //翻页
    const pageChange = useCallback((v) => {
        setCurrentPage(v)
    }, [])
    useEffect(() => {
        doRequest()
    }, [currentPage])

    
    //搜索
    const doSearch = useCallback((v) => {
        //请求之前将type、currentPage重置
        setType(0)
        setCurrentPage(0)
        doRequest()//问题:doRequest中如何能拿到type=0、currentPage=0,或者说这段代码本身设计上存在问题如何写一个语义更清晰的结构了?
        
    }, [doRequest])
    return (
        <div>
            <input value={searchValue} onChange={setSearchValue} onClick={doSearch}/>
            <Pagination currentPage={currentPage} onChange={pageChange}/>
            <Tab type={type} onChange={tabChange}>
        </div>
    )
}
问题:doRequest依赖好几个变量,其中一部分变量的改变必须导致其他变量重置,场景就是:两tab切换的无限加载,tab切换(type)必然会导致当前页(currentPage)重置,在我司接口设计上他们是同一个接口的不同字段理应只用一个doRequest,
    const doRequest = useCallback(() => {
        request.post({
            type,
            currentPage
        })
    }, [type, currentPage])

    useEffect(() => {
        setCurrentPage(0)
    }, [type])
    useEffect(() => {
        doRequest()
    }, [doRequest])
但存在一个问题以上代码可能会有两个或者两个以上的请求发出(你并不能保证请求返回的先后顺序)
那把代码改成下面这样试试:
    const doRequest = useCallback(() => {
        request.post({
            type,
            currentPage
        })
    }, [type, currentPage])
    useEffect(() => {
        setCurrentPage(0)
        doRequest()
    }, [type])
以上代码虽然只发一个请求出去,但不能做到doRequest中的currentPage=0
如果用Class component;问题很好解决
    doRequest = () => {
        request.post({
            type: this.state.type,
            currentPage: this.state.currentPage
        })
    }
    changeType = (v) => {
        this.setState({
            currentPage: 0,
            type: v
        }, () => {
            this.doRequest()
        })
    }
在react-hook中type、currentPage在接口上是统一的但是在逻辑上是对立的,那如何用hook解决上面所描述的问题了?
最后求解答 特别是第二个问题 谢谢了!!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文