项目背景:Taro下的React。小说目录,根据目前正在阅读的小说章节打开目录后会直接定位到所在目录位置。个人感觉是React ref的小bug
关键代码:
JS部分
const hightLight= useRef<HTMLDivElement>(null)
useEffect(()=>{
console.log(hightLight)
if (hightLight.current) {
hightLight.current.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
}
},[hightLight])
body:
{menu?.list.map((item:MenuDetail)=>{
return(
<View className={item.id==bookId?'light nut-cell':'nut-cell'} key={item.id} onClick={()=>{GoRead(item)}} ref={item.id==bookId?hightLight:null}>
XXXXXXXX
</View>
)})
}
一开始是这样的代码,dom元素情况是循环menu列表,然后给特定的dom打上ref标签。但是在开发过程中,发现在useEffect打印出来的HightLight内容为null,也导致了无法正确滑动到指定的dom元素上。在编辑器里面保存一下,就可以获取到ref内容且可以定位,但是刷新网页或者重新进入网页,打印的HightLight始终是null。虽然useEffct是在dom渲染完成之后的,但是也没搞清为什么在useEffect里面获取不到,指向的是初始值也就是const hightLight= useRef<HTMLDivElement>(null),如果把null改成 " ",则会打印underfind。应该是我的dom元素也是要根据渲染的情况来的,而且数目有点多,useEffect已经执行了,ref标签都还没来得及打上,导致效果出不来。尽管用useEffect的副作用绑定useRef的值也没用。
解决方法:
思路:用useEffect的思路,useEffect当指定的数据发生变化的时候会再执行一次逻辑。既然是ref来不及打上标签。那么可以在刚进去的时候设置一个定时器,因为定时器肯定是最后才执行的,再配合useState,把State的值给useEffect,就可以做到进入页面后state更新,导致useEffect再执行一次。虽然这个方法有点笨且有造成不必要的浪费。但是也算是个简单的解决方法。
关键代码:
const [count, setCount] = useState(0); //随意定义一个计数器
//制造一个开局的定时器。注意!一定要return出去清除定时器,副作用参数写 【】,这样就可以开始的时候过0.1秒执行一次让count的值发生变化,并且清楚定时器。一定要写[],不然会一直执行。
useEffect(() => {
const timer = setTimeout(() => {
setCount(count + 1);
}, 100);
return () => clearTimeout(timer);
}, []);
//在useEffect里面副作用用上count。当执行定时器的时候,dom元素已经渲染好,并且ref也打上了。此时定时器执行,count发生变化,就可以再一次触发这个useEffect,实现对应的ref的功能。定时器时间设置短一点,但是也要在100以上。
useEffect(()=>{
if (hightLight.current) {
hightLight.current.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
}
},[count])
如果有更好的办法,希望指正🙏🙏。谢谢