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
这个结论该如何解释?
数据矛盾
需求:
列表展示页:分两部分 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) => {
setType(v)
}, [])
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解决上面所描述的问题了?