在我使用 Vite 的 React 应用程序中,我使用 react-router 创建了一个基本路由器,其中有一个父元素渲染我的根布局,里面有一个 Outlet,以及在第一个子元素上有一个加载器...
在我使用 Vite 的 React 应用程序中,我创建了一个基本路由器,使用 react-router
父元素渲染根布局 Outlet
,并在父路由的第一个子元素上放置加载器。问题是,当我在子元素上导航时,应用程序根本不会渲染任何内容,只会呈现一个白屏,直到加载器完成数据获取。我的应用程序结构如下所示。
App.js
const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />,
children:
[
{
index: true,
element: <HomePage />,
loader: getApplications
},
{
path: 'application/:applicationID',
element: <h2>Single application page</h2>,
}
]
},
{
path: '/login',
element: <LoginPage />,
action: userLogin
}
]);
const App = () => {
return (
<>
<ToastContainer
position='top-right'
autoClose={5000}
hideProgressBar={true}
newestOnTop={true}
closeOnClick={true}
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme='colored'
/>
<RouterProvider router={router} />
</>
);
};
export default App;
Root.js
const RootLayout = () => {
const navigate = useNavigate();
const navigation = useNavigation();
const token = localStorage.getItem('token');
const isPageLoading = navigation.state === 'loading';
console.log(isPageLoading);
useEffect(() => {
if (!token) {
navigate('/login');
}
}, [token, navigate]);
if (token) {
return (
<Layout>
<Navbar />
<Layout>
<PageContent>
{isPageLoading
? <LoadingSpinner />
: <Outlet />
}
</PageContent>
<PageFooter />
</Layout>
</Layout>
);
}
};
export default RootLayout;
Home.js
const HomePage = () => {
const data = useLoaderData();
console.log(data);
return (
<>
<PageHeader pageTitle='Αιτήσεις' hasBack={false} />
</>
);
};
export default HomePage;
应用程序加载器.js
const getApplications = async () => {
const token = localStorage.getItem('token');
let data = {};
try {
const response = await axios.get(appsEndPoint(), {
headers: {
'Content-Type': 'application/json',
'Authorization': `token ${token}`
},
timeout: 30000
});
data = response.data;
return data;
} catch (error) {
if (isAxiosError(error)) {
console.log(error);
toast.error(error.message);
return null;
}
}
};
export default getApplications;
我最近在课程的帮助下创建了完全相同的登录名,它运行良好,在 RootLayout
显示加载微调器的同时呈现,加载器完成获取后,它会呈现带有数据的出口,正如我们预期的那样。但出于某种原因,在我的应用程序上,它只是在数据出现之前什么都不显示,然后将所有内容吐到屏幕上。
之前 调用 。换句话说,加载器完成并返回获取的数据, 然后 获取数据时显示加载指示。查看 延迟 数据 指南 .
以下是执行此操作的代码重构示例:
import { defer } from "react-router-dom";
const getApplications = async () => {
const token = localStorage.getItem( 'token' );
try {
const response = await axios.get(appsEndPoint(), {
headers: {
'Content-Type': 'application/json',
'Authorization': `token ${ token }`
},
timeout: 30000
});
return response.data;
} catch(error) {
if (isAxiosError(error)) {
console.log(error);
toast.error(error.message);
}
throw error;
}
};
const getApplicationsDeferred = () => {
return defer({
applications: getApplications(),
});
};
export default getApplicationsDeferred;
import React from 'react';
import { Await, useLoaderData } from "react-router-dom";
const HomePage = () => {
const data = useLoaderData();
return (
<Suspense fallback={<LoadingSpinner />}>
<Await
resolve={data.applications}
errorElement={<p>Error loading applications.</p>}
>
{(applications) => {
console.log(applications);
return (
<>
...
<PageHeader pageTitle='Αιτήσεις' hasBack={ false } />
...
</>
)
}}
</Await>
</Suspense>
);
};
export default HomePage;
您现在可能不需要根布局中的“加载”UI,只需无条件渲染, Outlet
以便嵌套路线立即可用/可访问。
<Layout>
<Navbar />
<Layout>
<PageContent>
<Outlet />
</PageContent>
<PageFooter />
</Layout>
</Layout>
这是一个正在运行的演示,它为了演示目的获取假的 JSON 数据,但异步数据/加载流程是相同的。