@Alexandr199

Как реализовать анимацию в актуальной странице при навигации?

Хочу реализовать функционал как в dtf, где между переходами над страницами срабатывает анимация загрузки под Header в актуальной странице.

Но не совсем понимаю за счёт чего такой эффект. Явно тут не стандартные NavLink, ибо при ее использовании тебя сразу перекидывает на другую страницу.

Я так понимаю этот эффект достигается с помощью useHistory когда при get запросе сперва включается анимация, а потом когда данные пришли успешно тебя перекидывает?

К сожалению у меня сейчас нету возможности проверить эту теорию, но вопрос все не отпускает меня.
  • Вопрос задан
  • 327 просмотров
Решения вопроса 1
KulakovAngel
@KulakovAngel
Full Stack Developer (Node.JS)
Явно тут не стандартные NavLink, ибо при ее использовании тебя сразу перекидывает на другую страницу.

Вы правы. Вариантов, почему это происходит, может быть несколько:
  • Динамический импорт
  • Предварительная загрузка данных


Реализовать это можно двумя способами:
  1. Что-то сделать с NavLink
  2. Что-то сделать с роутером


Предварительный импорт - когда нам заранее не известен компонент, который требуется подгрузить, реализуется через <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>
  );
};
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы