我需要展示路线更改之间的旋转器。像这样:
https://codesandbox.io/s/beautiful-williamson-dvxcj
这就是我想出的:
function LayoutLoaderTransition() {
const [, setForceUpdateBoolean] = useState(false); // A BOOLEAN STATE TO FORCE RE-RENDERS
const location = useLocation(); // WILL RE-RENDER WHEN THE LOCATION CHANGES
const lastPathname_ref = useRef(null); // REF TO REMEMBER THE LAST PATHNAME (ROUTE)
const forceUpdate = useCallback(() => { // CALLBACK TO FORCE UPDATE THIS COMPONENT
setForceUpdateBoolean(prevState => !prevState); // TOGGLE BOOLEAN STATE
}, []);
if (lastPathname_ref.current === null) { // ON FIRST RENDER, LAST PATH REF IS NULL
lastPathname_ref.current = location.pathname; // INITIALIZE IT WITH CURRENT RENDER
}
useEffect(() => { // EFFECT TO CHECK IF THERE'S A NEW ROUTE
if (lastPathname_ref.current !== location.pathname) { // IF NEW ROUTE IS DIFFERENT THAN LAST
lastPathname_ref.current = location.pathname; // UPDATE REF
setTimeout(() => forceUpdate(), 500); // FORCE UPDATE AND LAST PAHTNAME WILL BE === NEW
}
}, [forceUpdate, location.pathname]);
return (
<React.Fragment>
<Header />
{lastPathname_ref.current !== location.pathname ? ( // WHEN NEW PATHNAME !== LAST PATHNAME
<div>Loading</div> // SHOW LOADING
) : ( // OTHERWISE SHOW COMPONENT <Main/>
<div>
<Main />
</div>
)}
<Footer />
</React.Fragment>
);
}
// <Main/> IS BEING UN-MOUNTED AND RE-MOUNTED BETWEEN ROUTE CHANGES
function Main() {
return (
<Switch>
<Route exact path={HOME} component={Home} />
<Route exact path={ROUTE1} component={Component1} />
<Route exact path={ROUTE2} component={Component2} />
</Switch>
);
}
它可以工作,但是我发现它有点奇怪,因为我要在每个<Switch>
上卸载<Route>
和所有<Main/>
并将其重新安装。通常,它们只会挂载一次,并且只能在两次路由更改之间重新渲染。
这是不好的做法吗?通过在每次更改路线时重新安装“路由信息”,我是否有失去任何“路由信息”的风险?还是可以吗?
注意1::此处的500ms setTimeout()
仅用于演示。在实际代码中,我将不需要它。微调器将显示,并将显示在屏幕上,直到React完成渲染下一页为止。在速度较慢的手机上,旋转器会显示得更长一些,而在速度较快的手机上则相反。
查看没有超时的外观,Route2上呈现了一个沉重的组件。在绘制繁重的路线时,用户可以看到微调器。
额外:
之所以这样做,是因为在移动设备(CPU功率较低)上,新路径需要花费一些时间来渲染,而且如果我不显示微调器,则UX会很糟糕。用户单击<Link/>
,直到新页面完成渲染,感觉什么都没发生。因此,我需要在路线更改之间显示一个加载程序。
注意:
没有进行API调用。当应用程序第一次加载时,数据已经完全存在。如果有API调用,则可以在每个组件内部处理loading
状态,而不是像在这里那样在更高级别上进行。