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

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解决上面所描述的问题了?
最后求解答 特别是第二个问题 谢谢了!!!
阅读 8.3k
2 个回答
新手上路,请多包涵
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏