账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    react-hook中setTimeout、useEffect执行顺序与数据矛盾
    • 2020-01-01 00:00
    • 10
    19
    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解决上面所描述的问题了?
    

    最后求解答 特别是第二个问题 谢谢了!!!

    0
    打赏
    收藏
    点击回答
    您的回答被采纳后将获得:提问者悬赏的 10 元积分
        全部回答
    • 0
    更多回答
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部