使用 useState 和 useEffect 每 8 秒更新一次滚动位置?
update scroll position every 8 seconds with useState and useEffect?
我正在为我的 Web 应用程序使用 next js。我想编写使用 useState
更新滚动位置的函数。出于某种原因,useState 没有正确更新自身,因为我还需要计算函数的最大值。这是我的代码:
const [lazyProgress,setLazyProgress] = useState(0);
const [lazyProgressMax,setLazyProgressMax] = useState(0);
function lazyProgressUpdate(){
const scrollTotal = document.documentElement.scrollTop;
const heightWin = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scroll = scrollTotal / heightWin * 100;
setLazyProgress(scroll);
if(lazyProgress > lazyProgressMax){
setLazyProgressMax(lazyProgress);
}
console.log(lazyProgress,lazyProgressMax)
}
useEffect(()=>{
const timer = setInterval(()=>{
lazyProgressUpdate();
},8000);
return ()=>{
clearInterval(timer);
}
},[]);
在上面的代码片段中,lazyProgress 和 lazyProgressMax 在函数中始终为 0。所以他们都没有更新。
我该如何解决这个问题
问题
您遇到的问题实际上是 setInterval 回调中状态的陈旧封闭。此回调关闭初始状态,因此它会看到所有内容。
解决方案
排队滚动更新并使用单独的 useEffect
挂钩,依赖 lazyProgress
到 check/set lazyProgressMax
状态。
const [lazyProgress, setLazyProgress] = useState(0);
const [lazyProgressMax, setLazyProgressMax] = useState(0);
function lazyProgressUpdate(){
const scrollTotal = document.documentElement.scrollTop;
const heightWin = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scroll = scrollTotal / heightWin * 100;
setLazyProgress(scroll); // <-- (1) update lazyProgress state
}
useEffect(() => {
const timer = setInterval(() => {
lazyProgressUpdate();
}, 8000);
return () => {
clearInterval(timer);
}
},[]);
useEffect(() => {
setLazyProgressMax(lazyProgressMax => { // <-- (3) functional state update
if (lazyProgress > lazyProgressMax) {
return lazyProgress; // <-- (4a) return new lazyProgress value
}
return lazyProgressMax; // <-- (4b) or previous state
});
}, [lazyProgress]); // <-- (2) lazyProgress as dependency
您需要在 useEffect 中创建函数,以防万一函数不再需要。
以下代码指导如何在useEffect中创建函数以及如何清除创建的间隔。
useEffect(()=>{
const lazyProgressUpdate = () => {
// function logic here
}
const timer = setInterval(() => {
lazyProgressUpdate()
}, 8000);
return () => {
clearInterval(timer);
}
},[]);
我正在为我的 Web 应用程序使用 next js。我想编写使用 useState
更新滚动位置的函数。出于某种原因,useState 没有正确更新自身,因为我还需要计算函数的最大值。这是我的代码:
const [lazyProgress,setLazyProgress] = useState(0);
const [lazyProgressMax,setLazyProgressMax] = useState(0);
function lazyProgressUpdate(){
const scrollTotal = document.documentElement.scrollTop;
const heightWin = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scroll = scrollTotal / heightWin * 100;
setLazyProgress(scroll);
if(lazyProgress > lazyProgressMax){
setLazyProgressMax(lazyProgress);
}
console.log(lazyProgress,lazyProgressMax)
}
useEffect(()=>{
const timer = setInterval(()=>{
lazyProgressUpdate();
},8000);
return ()=>{
clearInterval(timer);
}
},[]);
在上面的代码片段中,lazyProgress 和 lazyProgressMax 在函数中始终为 0。所以他们都没有更新。
我该如何解决这个问题
问题
您遇到的问题实际上是 setInterval 回调中状态的陈旧封闭。此回调关闭初始状态,因此它会看到所有内容。
解决方案
排队滚动更新并使用单独的 useEffect
挂钩,依赖 lazyProgress
到 check/set lazyProgressMax
状态。
const [lazyProgress, setLazyProgress] = useState(0);
const [lazyProgressMax, setLazyProgressMax] = useState(0);
function lazyProgressUpdate(){
const scrollTotal = document.documentElement.scrollTop;
const heightWin = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scroll = scrollTotal / heightWin * 100;
setLazyProgress(scroll); // <-- (1) update lazyProgress state
}
useEffect(() => {
const timer = setInterval(() => {
lazyProgressUpdate();
}, 8000);
return () => {
clearInterval(timer);
}
},[]);
useEffect(() => {
setLazyProgressMax(lazyProgressMax => { // <-- (3) functional state update
if (lazyProgress > lazyProgressMax) {
return lazyProgress; // <-- (4a) return new lazyProgress value
}
return lazyProgressMax; // <-- (4b) or previous state
});
}, [lazyProgress]); // <-- (2) lazyProgress as dependency
您需要在 useEffect 中创建函数,以防万一函数不再需要。
以下代码指导如何在useEffect中创建函数以及如何清除创建的间隔。
useEffect(()=>{
const lazyProgressUpdate = () => {
// function logic here
}
const timer = setInterval(() => {
lazyProgressUpdate()
}, 8000);
return () => {
clearInterval(timer);
}
},[]);