[英]React.useEffect hook and subscribing to a mousewheel event - the right approach
目標:
在組件安裝時訂閱一次鼠標滾輪event
。
使用newValue
更新組件的 state.scrollTop ,其中:
newValue = Math.max(0, state.scrollTop + event.deltaY)
編碼:
const [ state, setState ] = useState({ scrollTop: 0 });
useEffect(function subscribeToWheelEvent() {
const updateScroll = function(e) {
if(!!e.deltaY) {
const delta = Math.sign(e.deltaY) * 10.0;
const val = Math.max(0, state.scrollTop + delta);
console.log(delta, val);
setState({ scrollTop: val })
} else {
console.log('zero', e.deltaY);
}
}
window.addEventListener('mousewheel', updateScroll);
console.log('subscribed to wheelEvent')
return function () {
window.removeEventListener('mousewheel', updateScroll);
}
}, []);
預期結果:
state.scrollTop
值根據滾動方向將每個鼠標滾輪事件更新 +-10,如果newValue
小於 0,則上限為 0。
當前結果:
state.scrollTop
值沒有正確更新,在 0 和 10 之間切換,可能是因為它在 updateScroll 中被updateScroll
並保持為 0。
linter 通知我應該包含 state.scrollTop 作為效果的依賴項,但我不希望這樣,因為它應該在組件安裝時只執行一次。
跟隨 linter 會導致無限循環。
或者,將updateScroll
訂閱功能之外,然后根據updateScroll
建議,將updateScroll
添加到依賴項,並且(再次跟隨updateScroll
用useCallback(updateScroll, [state.scrollTop] )
包裝updateScroll
導致訂閱/取消訂閱滾輪事件每個scrollTop
變化。
替代代碼:
const [ state, setState ] = useState({ scrollTop: 0 });
const updateScroll = useCallback(function(e) {
if(!!e.deltaY) {
const delta = Math.sign(e.deltaY) * 10.0;
const val = Math.max(0, state.scrollTop + delta);
console.log(delta, val );
setState({ scrollTop: val })
} else {
console.log('zero', e.deltaY);
}
}, [ state.scrollTop ])
useEffect(function subscribeToWheelEvent() {
window.addEventListener('mousewheel', updateScroll);
console.log('subscribed to wheelEvent')
return function () {
window.removeEventListener('mousewheel', updateScroll);
console.log('unsubscribed to wheelEvent')
}
}, [ updateScroll ]);
題:
如何實現目標?
您可以將函數傳遞給setState
而不是關閉useEffect
處理程序中的state
變量。
該函數的參數是當前狀態,您需要返回新狀態。 這樣useEffect
不應該抱怨,因為你的useEffect
不依賴於狀態變量。
就像是:
const [ state, setState ] = useState({ scrollTop: 0 });
useEffect(function subscribeToWheelEvent() {
const updateScroll = function(e) {
if(!!e.deltaY) {
setState((currentState)=>{
const delta = Math.sign(e.deltaY) * 10.0;
const val = Math.max(0, currentState.scrollTop + delta);
return {scrollTop:val}
})
}
} else {
console.log('zero', e.deltaY);
}
}
window.addEventListener('mousewheel', updateScroll);
console.log('subscribed to wheelEvent')
return function () {
window.removeEventListener('mousewheel', updateScroll);
}
}, []);
有幾個問題:
我沒有鼠標滾輪,但不推薦使用事件mousewheel
- 您可能想要使用其他東西。 我訂閱了scroll
事件。
我不確定您要使用 delta 和 val 計算什么,但是const val = Math.max(0, state.scrollTop + delta)
似乎沒有按我的預期工作。 您的意思是計算 CURRENT scrollTop 值,而不是存儲的值嗎?。 無論哪種方式,這都是導致您的值返回10
,也是導致重新渲染循環的原因。
所以我認為這就是你所追求的:
const [state, setState] = useState({ scrollTop: 0 })
const updateScroll = useCallback(() => {
if (window.pageYOffset) {
const delta = Math.sign(window.pageYOffset) * 10.0
const val = Math.max(0, window.pageYOffset + delta)
setState({ scrollTop: val })
} else {
console.log('zero', window.pageYOffset)
}
}, [])
useEffect(
function subscribeToWheelEvent () {
console.log('subscribed to wheelEvent')
window.addEventListener('scroll', updateScroll)
return function () {
window.removeEventListener('scroll', updateScroll)
}
},
[updateScroll]
)
console.log(state.scrollTop)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.