Явно тут не стандартные NavLink, ибо при ее использовании тебя сразу перекидывает на другую страницу.
Вы правы. Вариантов, почему это происходит, может быть несколько:
- Динамический импорт
- Предварительная загрузка данных
Реализовать это можно двумя способами:
- Что-то сделать с NavLink
- Что-то сделать с роутером
Предварительный импорт - когда нам заранее не известен компонент, который требуется подгрузить, реализуется через
<React.Suspense fallback={<>Loading...</>}>
,
React.lazy()
и "import" как функцию:
import('./ImportedPage')
. Концептуальный пример (и
ссылка на песочницу):
// index.jsx
// "const Page = ..." - это концепция, в реальности в роутере
// можно получить название страницы (или id), которые и будут названием файла.
import React from 'react';
function App() {
const Page = React.lazy(() => import('./ImportedPage'))
return (
<div>
<React.Suspense fallback={<>Loading...</>}>
<Page />
</React.Suspense>
</div>
);
}
export default App;
// ImportedPage.jsx, то что импортирует главный компонент.
import React from 'react';
function Page() {
return (
<div>
<h1>Some Page, preloading required</h1>
</div>
);
}
export default Page;
Вместо "<>Loading...>" можете реализовать "полосу загрузки".
Второй вариант - предварительная загрузка данных. Допустим, компоненту (странице, на которую собираемся перейти), требуются данные с сервера (скажем, список вакансий с картинками). Так вот, вначале запрашиваем данные от сервера, показываем прелоадер (в Вашем случае - полосу загрузки), и только когда данные получены - показываем готовую страницу. Если используете редакс, то при отправке асинхронного действия можно в редуктор запостить что-то типа "LOADING_BAR_SHOW", а после окончания загрузки данных (при получении ответа сервера) - два действия, вроде "PAGE_SHOW" (с payload, по которому можно определить необходимую страницу) и "LOADING_BAR_CLOSE" (который спрячет полосу загрузки).
Также давайте рассмотрим реализацию изменения поведения NavLink. При клике делаем preventDefault, после чего выполняем необходимые операции (динамические import, запросы к серверу, что угодно), а при завершении этого дела - пушим URL в history. У меня получилось нечто подобное (
ссылка на песочницу):
import React from 'react';
import { Switch, Route, Link, useHistory } from 'react-router-dom';
import BarLoader from 'react-bar-loader';
export default () => {
const [data, setData] = React.useState();
const [isLoading, toggleLoading] = React.useState(false);
const history = useHistory();
const getData = () => (
new Promise((res, rej) => {
// Здесь можем выполнять любую нужную операцию - например, запрос к серверу
setTimeout(() => res('Some data, may be from server...'), 2000);
}).then(data => setData(data))
);
const handleLinkClick = (e) => {
toggleLoading(true)
e.preventDefault();
const pathname = e.target.pathname;
getData()
.then(data => {
toggleLoading(false)
history.push(pathname)
})
};
// Просто обертка над Link, чтобы не писать всегда onClick={handleLinkClick}
const WaitingLink = (props) => <Link onClick={handleLinkClick} {...props}>{props.children}</Link>
return (
<div>
<header>
{
isLoading && <BarLoader color='#1D8BF1' height='3' />
}
<ul>
<li><WaitingLink to={'/'}>Home Page</WaitingLink></li>
<li><WaitingLink to={'/somepage'}>Some Other Page</WaitingLink></li>
<li><WaitingLink to={'/somepage2'}>Some Other Page 2</WaitingLink></li>
</ul>
</header>
<Switch>
<Route exact path={'/'}>
<div style={{background: '#ff8888'}}>
<h1>Home Page</h1>
</div>
</Route>
<Route exact path={'/somepage'}>
<div style={{background: '#88ff88'}}>
<h1>Some Other Page</h1>
</div>
</Route>
<Route exact path={'/somepage2'}>
<div style={{background: '#8888ff'}}>
<h1>Some Other Page 2</h1>
{/*Попробуем данные из состояния взять, которые получены при клике*/}
{/*В реальности это может быть redux-srore*/}
<p>{data ? data : (getData(), null)}</p>
</div>
</Route>
</Switch>
</div>
);
};