持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
前言
在之前的篇幅中我们讲到了原生页面和React路由在历史切换导致滚动条的行为变换。
结合之前的实践,这次我们想要探讨的是如何让react路由切换像原生页面切换一样符合逻辑与直觉。
实际上,并非react路由会出现这种情况,基于history下的dom切换都会有这种情况,而之前的实践就是为了处理这种情况。
前进后退下的页面调用
在项目开始前,我们基于v5路由的工程下有这样几个页面:
import {BrowserRouter as Router,Route,Switch,Link} from "react-router-dom"
import Home from "./components/Home"
import Users from "./components/User";
function Index(){
return <>
<Link to='/home'>home</Link>
<Link to='/users'>users</Link>
</>
}
function App() {
return (
<div className="App">
<Router>
<Switch>
<Route path='/' component={Index} exact></Route>
<Route path='/home' component={Home} exact></Route>
<Route path="/users" component={Users} exact></Route>
</Switch>
</Router>
</div>
);
}
export default App;
//主页面
import { useState } from "react"
import { NavLink } from "react-router-dom"
const Home = () => {
const [display, setDisplay] = useState(true)
return <>
{
display ? (<>
<div style={{
width: '500px',
background: 'red',
height: "400vh",
display: display ? 'block' : 'none'
}}>
</div>
<NavLink
to="/users"
>
user
</NavLink>
<div style={{
width: '500px',
background: 'red',
height: "400vh",
display: display ? 'block' : 'none'
}}>
</div>
</>) : null
}
</>
}
export default Home
import { useEffect } from "react"
import { NavLink } from "react-router-dom"
function Users() {
console.log("run")
useEffect(() => {
console.log("effect start")
}, [])
return <>
<div style={{
width: '500px',
background: '#009c9c',
height: "30vh"
}}>
<NavLink
to="/home"
>
home
</NavLink>
</div>
<NavLink
to="/users"
>
user
</NavLink>
<div style={{
width: '500px',
background: 'green',
height: "30vh"
}}>
</div>
</>
}
export default Users
当我们点击跳转到/home页面,下滑跳转到/user页面。观察控制台输出:
此时控制台的输出证明了useEffect执行了。
当我们回退页面,useEffect并没有执行。
再次进入,useEffect再次执行:
基于现象我们可以初步得出结论: 当路由再次进入时,当前useEffect会再次执行,组件内部会运行。而return的dom节点是否渲染则是根据内部的diff结果去处理。
回退页面滚动位置的复原
在上面的前进后退处理中,我们能看到滚动条的复原,结合之前的测试,我们是基于会退页面存在滚动高度而处理的,当我们回退的页面初始高度没有滚动条呢?
通过模拟数据请求延迟页面渲染,我们对homo组件进行如下处理:
import { useState,useEffect } from "react"
import { NavLink } from "react-router-dom"
const Home = () => {
const [display, setDisplay] = useState(false)
useEffect(() => {
const timer = setTimeout(()=>{
setDisplay(true)
},1000)
return () => {
clearInterval(timer)
}
}, [])
return <>
{
display ? (<>
<div style={{
width: '500px',
background: 'red',
height: "400vh",
display: display ? 'block' : 'none'
}}>
</div>
<NavLink
to="/users"
>
user
</NavLink>
<div style={{
width: '500px',
background: 'red',
height: "400vh",
display: display ? 'block' : 'none'
}}>
</div>
</>) : null
}
</>
}
export default Home
我们先在home组件下滑到中间位置,然后点击跳转。
接着再次回退,我们期待着页面能够复原滚动条位置,然而当数据1s请求后,数据渲染dom,此时滚动条置顶了。
结合之前文章的测试,我们初步了解到置顶的原因是因为初始页面并不存在滚动条。然而这种现象在常见的前端路由模式下依旧存在。
小结
- 历史记录的前进回退中,组件在进入时会重新执行。
- 初始页面是否有滚动高度决定了回退的页面是否能够复原滚动条。