Closed qingant closed 5 years ago
@qingant执行到 componentWillUnactivate
生命周期的时候,界面已经被卸载了,所以不能再这里记录位置
@qingant 可以考虑在切换页面的事件上记录位置,比如我点击一个按钮会切换到一个页面,那就可以在按钮的点击事件里写
@qingant 可以考虑在切换页面的事件上记录位置,比如我点击一个按钮会切换到一个页面,那就可以在按钮的点击事件里写
切换页面的事件逻辑往往是在别的组件里面,比方list里面装elem,不可能在elem里面记录list的scroll(当然技术上也可以,但抽象上不太好)
在bindLifeCycle修饰的对象里面,是不是可以得到自己的状态呢?比方处于Unactivate的状态
感谢回复,我现在用这样的办法来解决:
componentDidActivate() {
console.log('restore', this.state)
setTimeout(e => {this.refs.scroller.scrollTop = this.state.scrollTop;}, 10);
this.state.activated = true
}
componentWillUnactivate() {
this.state.activated = false
}
onScroll() {
if (this.state.activated) {
this.state.scrollTop = this.refs.scroller && this.refs.scroller.scrollTop
}
}
it works!
@qingant Good
我自己实现一个自动恢复的hook,你可以参考一下:
import React, { useState, useRef, useEffect } from 'react';
import { useKeepAliveEffect } from 'react-keep-alive';
function isEqualAndTruthy(
newInputs?: React.DependencyList,
lastInputs?: React.DependencyList
) {
if (!newInputs || !lastInputs) {
return false;
}
if (newInputs.length !== lastInputs.length) {
return false;
}
for (let i = 0; i < newInputs.length; i++) {
if (newInputs[i] !== lastInputs[i]) {
return false;
}
}
return true;
}
export default function useScrollRestoration(deps?: React.DependencyList) {
const [scrollY, setScrollY] = useState<number | null>(null);
useKeepAliveEffect(() => {
let ticking: number | null = null;
const handler = () => {
if (ticking === null) {
ticking = window.requestAnimationFrame(() => {
setScrollY(window.scrollY);
ticking = null;
});
}
};
window.addEventListener('scroll', handler);
return () => {
window.removeEventListener('scroll', handler);
if (ticking !== null) {
window.cancelAnimationFrame(ticking);
}
};
});
const savedDeps = useRef(deps);
const savedCallback = useRef(() => {});
useEffect(() => {
savedCallback.current = () => (savedDeps.current = deps);
});
useKeepAliveEffect(() => {
if (scrollY !== null) {
const y = isEqualAndTruthy(savedDeps.current, deps) ? scrollY : 0;
window.scrollTo(0, y);
}
return () => {
savedCallback.current();
};
});
}
用的时候只需放到对应页面下
export default function PageA() {
// 依赖发生变化时页面回到顶部,不变时还原滚动位置
useScrollRestoration([]);
// ...
}
@pan-jiaquan 可以,有空研究一下你的代码
@pan-jiaquan 我的页面是一个滚动加载的页面,我发现会造成同一次请求会触发两次
试着用bindLifeCycle拦截,手动处理scroll restore,发现在componentWillUnactivate的时候,scrollTop就意外地变成了0
而在onScroll里面每次scroll后记录位置,也会在unactivate后变成0,似乎在挂载到别的地方的时候重新scroll了。