Програмно орієнтуватися за допомогою реактора маршрутизатора V4


336

Я щойно замінив react-routerз v3 на v4.
Але я не впевнений, як програмно орієнтуватися у функції члена a Component. тобто у handleClick()функції, до якої я хочу перейти /path/some/whereпісля обробки деяких даних. Раніше я це робив:

import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')

Але я не можу знайти такі інтерфейси у v4.
Як я можу переходити за допомогою v4?


3
Ви можете отримати доступ до об’єкта історії в v4 через реквізити: this.props.history.push ('/')
colemerrick

6
Що робити, якщо ви хочете отримати доступ до нього з іншого місця, ніж з Component? Наприклад, всередині редукційних дій.
Максим С

73
інколи мені цікаво, чому так складно просто перейти з однієї посилання на іншу =))
Thai Tran

12
Можна було б подумати, що перенаправлення в цей день і вік не буде настільки складним.
ДжонАллен

Я вважаю цю публікацію корисною: medium.com/@anneeb/redirecting-in-react-4de5e517354a
BioData41

Відповіді:


414

Якщо ви орієнтуєтесь на середовища браузера, вам потрібно використовувати react-router-domпакунок замість react-router. Вони слідують такому ж підходу , як React зробили для того, щоб відокремити ядро, ( react) і код платформи конкретного, ( react-dom, react-native) з тонким розходженням , що вам не потрібно встановлювати два окремих пакетів, так як пакети середовища містять всі тобі потрібно. Ви можете додати його до свого проекту як:

yarn add react-router-dom

або

npm i react-router-dom

Перше, що вам потрібно зробити - це забезпечити <BrowserRouter>як найвищий батьківський компонент у вашій програмі. <BrowserRouter>використовує historyAPI HTML5 та керує ним для вас, тож вам не доведеться турбуватися про його інстанціювання та передачу його <BrowserRouter>компоненту в якості опори (як це потрібно було зробити в попередніх версіях).

У програмі V4 для програмного навігації вам потрібно отримати доступ до historyоб'єкта, який доступний через React context, доки у вас є компонент <BrowserRouter> постачальника як самий верхній з батьків у вашій програмі. Бібліотека розкриває через контекст routerоб'єкт, який сам містить historyяк властивість. historyІнтерфейс пропонує кілька методів навігації, такі як push, replaceі goBack, серед інших. Ви можете перевірити весь перелік властивостей та методів тут .

Важлива примітка для користувачів Redux / Mobx

Якщо ви використовуєте функцію redux або mobx як свою бібліотеку управління державою у вашій програмі, можливо, у вас виникли проблеми з компонентами, які мають бути відомими місцеположенням, але не повторюватися після запуску оновлення URL-адреси.

Це відбувається тому, що react-routerпереходить locationдо компонентів за допомогою контекстної моделі.

Як підключення, так і спостерігач створюють компоненти, методи методу shouldComponentUpdate дозволяють дрібне порівняння їх поточного реквізиту та їх наступних реквізитів. Ці компоненти відновляться лише тоді, коли зміниться хоча б одна опора. Це означає, що для того, щоб вони оновлювались, коли місцеположення змінюється, їм потрібно буде запропонувати опору, яка змінюється, коли місцеположення змінюється.

Два підходи до вирішення цього питання:

  • Оберніть ваш підключений компонент без доріжок <Route />. Поточний locationоб'єкт є одним із реквізитів, що <Route>передає компонент, який він надає
  • Оберніть ваш підключений компонент компонентом withRouterвищого порядку, який насправді має такий же ефект і впорскується locationяк опора

Виходячи з цього, існує чотири способи програмно орієнтуватися впорядковано за рекомендаціями:

1.- Використання <Route>компонента

Він пропагує декларативний стиль. До <Route />версії v4 компоненти були розміщені у верхній частині ієрархії компонентів, заздалегідь потрібно продумати структуру ваших маршрутів. Однак тепер ви можете мати <Route>компоненти в будь-якому місці вашого дерева, що дозволяє вам мати більш точний контроль за умовно візуалізацією залежно від URL-адреси. Routeвпорскує match, locationа в historyякості реквізиту в компонент. Методи навігації (такі як push, replace, goBack...) доступні як властивості historyоб'єкта.

Є 3 способи робить що - то з Route, використовуючи або component, renderабо childrenреквізит, але не використовувати більше одного в тому ж самому Route. Вибір залежить від випадку використання, але в основному перші два варіанти відображатимуть ваш компонент лише у тому випадку, якщо він pathвідповідає розташуванню URL-адреси, тоді як з childrenкомпонентом буде виведено, чи збігається шлях з місцеположенням чи ні (корисно для налаштування інтерфейсу користувача на основі URL-адреси) відповідність).

Якщо ви хочете , щоб налаштувати вихід компонентного рендеринга , вам потрібно обернути компонент в функції і використовувати renderопцію для того, щоб перейти до компоненті будь-які інші реквізиту ви бажаєте, крім match, locationі history. Приклад ілюстрації:

import { BrowserRouter as Router } from 'react-router-dom'

const ButtonToNavigate = ({ title, history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    {title}
  </button>
);

const SomeComponent = () => (
  <Route path="/" render={(props) => <ButtonToNavigate {...props} title="Navigate elsewhere" />} />
)    

const App = () => (
  <Router>
    <SomeComponent /> // Notice how in v4 we can have any other component interleaved
    <AnotherComponent />
  </Router>
);

2.- Використання withRouterHoC

Цей компонент вищого порядку вводить ті ж реквізити, що і Route. Однак це обмежує обмеження, що у вас може бути лише 1 HoC на файл.

import { withRouter } from 'react-router-dom'

const ButtonToNavigate = ({ history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    Navigate
  </button>
);


ButtonToNavigate.propTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired,
  }),
};

export default withRouter(ButtonToNavigate);

3.- Використання Redirectкомпонента

Надання заходу <Redirect>перейде до нового місця. Але майте на увазі, що за замовчуванням поточне місце розташування замінюється новим, як перенаправлення на сторону сервера (HTTP 3xx). Нове місце розташування надається toопорою, яка може бути рядком (URL-адресою для переадресації) або locationоб'єктом. Якщо ви хочете, замість цього, натиснути новий запис на історію , також pushвведіть опору та встановіть їїtrue

<Redirect to="/your-new-location" push />

4.- Доступ routerвручну через контекст

Трохи відлякує, оскільки контекст все ще є експериментальним API, і він, ймовірно, може зламати / змінити в майбутніх випусках React

const ButtonToNavigate = (props, context) => (
  <button
    type="button"
    onClick={() => context.router.history.push('/my-new-location')}
  >
    Navigate to a new location
  </button>
);

ButtonToNavigate.contextTypes = {
  router: React.PropTypes.shape({
    history: React.PropTypes.object.isRequired,
  }),
};

Потрібно сказати, що є також інші компоненти маршрутизатора, призначені для екосистем, які не є браузером, такі як <NativeRouter>копія навігаційного стеку в пам'яті та цільових платформ React Native, доступних через react-router-nativeпакет.

Для будь-якої подальшої довідки, не соромтеся поглянути на офіційні документи . Також є відео, зроблене одним із співавторів бібліотеки, яке забезпечує досить круте вступ у реагування на маршрутизатор v4, підкреслюючи деякі основні зміни.


2
Я використовую V4, і вищезазначене працює чудово. Я витратив неабияку кількість часу на роздуми з маршрутизатором V4, оскільки, здається, є дивні варіанти, але вище, безумовно, працює. Я припускаю, що ви імпортуєте withRouterзreact-router-dom
Сем Парментер

3
Я імпортую withRouterз react-router-dom. History.push змінює URL-адресу, але, схоже, не завантажує, <Route>поки я не
змушу

1
@rauliyohmc Я помилявся з цього приводу. Проблема полягає в тому, що я маю <Router> всередині прикрашений компонент React @observer, який викликає цю проблему . Робота навколо полягає в тому, щоб провести @withRouterкожен такий компонент React.
BreakDS

3
Для тих, хто стикається з цією чудовою відповіддю, withRouterпросто HOC, який використовує Routeпід кришкою. Що означає, що він використовує лише 3 реквізиту, історію, збіг та місцеположення . У наведеному вище прикладі виявляється, що pushце опора, яка withRouterдодала б ButtonToNavigate, але це не так. props.history.pushдоведеться використовувати замість цього. Сподіваюсь, це допомагає іншим, хто трохи розгубився.
vinnymac

39
Ого. browserHistory.push('/path/some/where')просто здається набагато простішим. Автори намагаються відмовитись від імперативного програмування, але іноді це просто працює краще!
люкс

149

Найпростіший спосіб зробити це:

this.props.history.push("/new/url")

Примітка:

  • Ви можете передати history propбатьківський компонент вниз до компонента, до якого потрібно викликати дію, якщо його немає.

10
Я використовую 4.0 маршрутизатор, але в реквізиті немає ключа історії. Як я можу це виправити?
Nicolas S.Xu

41
Якщо у вас немає this.props.historyу вашому компоненті, ви можете, import {withRouter} from 'react-router-dom'а потім export default withRouter(MyComponent)(або const MyComponent = withRouter(...)), і він вставить historyелемент у реквізит вашого компонента.
Malvineous

@Malvineous, що цікаво, про це не знав! Спробую!
Jikku Jose Jose

2
Мені, мабуть, не вистачає чогось принципового, тому що це для мене просто чудово, тому я не маю поняття, чому всі відповіді потребують таких тривалих пояснень.
Джошуа Пінтер

як запобігти перезавантаженню компонентів history.pushі просто запустити оновлення, як, коли ми натискаємо на<Link>
Рахул Ядав

55

У мене була подібна проблема при переході на React-Router v4, тому я спробую пояснити своє рішення нижче.

Будь ласка, не розглядайте цю відповідь як правильний спосіб вирішити проблему, я думаю, є хороший шанс, що виникне щось краще, коли React Router v4 стане більш зрілим і залишить бета (він може вже існувати, і я просто його не виявив) .

У контексті у мене виникла ця проблема, оскільки я час від часу використовую Redux-Sagaдля програмної зміни об'єкта історії (скажімо, коли користувач успішно підтверджує автентифікацію).

У документах React Router, подивіться на <Router> компонент, і ви зможете переконатися, що у вас є можливість передавати власний об’єкт історії через опору. Це суть рішення - ми поставляємо об'єкт історії , щоб React-Routerз глобального модуля.

Кроки:

  1. Встановіть модуль npm історії - yarn add history або npm install history --save
  2. створити файл, який називається history.jsу вашій App.jsпапці рівня (це було моїм уподобанням)

    // src/history.js
    
    import createHistory from 'history/createBrowserHistory';
    export default createHistory();`
  3. Додайте цей об’єкт історії до компонента маршрутизатора так

    // src/App.js
    
    import history from '../your/path/to/history.js;'
    <Router history={history}>
    // Route tags here
    </Router>
  4. Налаштуйте URL як і раніше, імпортуючи свій глобальний об'єкт історії:

    import history from '../your/path/to/history.js;'
    history.push('new/path/here/');

Тепер все має синхронізуватися, і ви також маєте доступ до способу налаштування об’єкта історії програмно, а не через компонент / контейнер.


5
Ця зміна спрацювала для мене, але лише тому, що я перебуваю за межами компонента. Якби я переміщався всередині такого компонента, як ОП, я використовував би підхід, запропонований @rauliyohmc, використовуючи реквізит, переданий Routeкомпонентом.
Ден Елліс

2
це рекомендований підхід від 08/17
Spets

2
@Spets У моєму випадку, якщо я використовую такий тип підходу, посилання буде оновлено належним чином після натискання, але компоненти не будуть надані належним чином (наприклад, після оновлення посилання компонент не оновлюється, якщо не змусити оновити сторінку). Де ви виявили, що це рекомендований підхід? Будь-які посилання / джерела?
круто

2
@ScottCoates Я розібрався, використовуючи приклад вище, дійсно, подавши історію як параметр, але після того, як я зробив налагодження модулів вузла самостійно. Існує поширена помилка, зроблена по всьому Інтернету, використовуючи імпорт "BrowserHistory as Router", коли натомість є ще один об'єкт під назвою Router сам по собі в останній версії react-router-dom. Використання цього в поєднанні з історією, створеною у прикладі вище, працює просто чудово.
круто

2
URL-адреса оновлюється, але сторінка не відображається на основі нового кореня. Будь-яке рішення? Чому тригерний маршрут такий складний? Люди, які проектують, реагують, не з розуму?
Nicolas S.Xu

43

TL; DR:

if (navigate) {
  return <Redirect to="/" push={true} />
}

Проста і декларативна відповідь полягає в тому, що вам потрібно користуватися <Redirect to={URL} push={boolean} />в поєднанні зsetState()

push: boolean - коли це правда, перенаправлення натисне новий запис на історію замість заміни поточного.


import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

Повний приклад тут . Детальніше читайте тут .

PS. У прикладі використовується ініціалізатори властивостей ES7 + для ініціалізації стану. Подивіться і тут , якщо вам цікаво.


5
На це слід прийняти відповідь. Найпростіше елегантне рішення! +1 для @lustoykov
Алі Аббас Джафрі

1
Я також встановив перехід назад до значення false у компонентDidUpdate, оскільки моя кнопка знаходиться в заголовку, інакше я перейду лише один раз.
peterorum

Це працює лише в тому випадку, якщо вам відомо про переспрямування під час завантаження сторінки. Якщо ви чекаєте повернення асинхронного дзвінка (тобто аутентифікації з Google чи чогось іншого), вам доведеться скористатися одним із history.push()методів.
бритохаллоран

Насправді, ви все ще можете використовувати декларативний характер реакції в поєднанні з компонентом <Перенаправлення />. Якщо сторінка не завантажується, ви можете перейти до іншого <Перенаправлення />
Любомира

@brittohalloran ідея цього методу, використовуючи відповідний маршрутизатор реагування, полягає в тому, щоб переконатися, що ви використовуєте setState для примусового повторного відображення.
Хтось Спеціальний

16

Використовуйте useHistoryгачок, якщо ви використовуєте функціональні компоненти

Ви можете використовувати useHistoryгачок, щоб отримати historyекземпляр.

import { useHistory } from "react-router-dom";

const MyComponent = () => {
  var history = useHistory();

  return (
    <button onClick={() => history.push("/about")}>
      Click me
    </button>
  );
}

useHistoryКрюк дає вам доступ до примірника історії , які ви можете використовувати для навігації.

Використовуйте historyвластивості всередині компонентів сторінки

Маршрутизатор React вводить деякі властивості, включаючи historyкомпоненти сторінки.

class HomePage extends React.Component {
  render() {
    const { history } = this.props;

    return (
      <div>
        <button onClick={() => history.push("/projects")}>
          Projects
        </button>
      </div>
    );
  }
}

Оберніть дочірні компоненти, withRouterщоб ввести властивості маршрутизатора

withRouterобгортка вводить компонентам властивості маршрутизатора. Наприклад, ви можете використовувати цю обгортку для введення маршрутизатора для виходу компонента кнопки виходу в меню користувача.

import { withRouter } from "react-router";

const LogoutButton = withRouter(({ history }) => {
  return (
    <button onClick={() => history.push("/login")}>
      Logout
    </button>
  );
});

export default LogoutButton;

11

Ви також можете просто використовувати реквізит для доступу до об’єкту історії: this.props.history.push('new_url')


5
Корисно лише тоді, коли компонент безпосередньо зійшов з маршрутизатора. Щоб ви не передавали
підказку

3
Якщо у вас немає this.props.historyу вашому компоненті, ви можете, import {withRouter} from 'react-router-dom'а потім export default withRouter(MyComponent)(або const MyComponent = withRouter(...)), і він вставить historyелемент у реквізит вашого компонента.
Malvineous

9

Крок 1. Імпортувати зверху є лише одне:

import {Route} from 'react-router-dom';

Крок 2. У маршруті пройдіть історію:

<Route
  exact
  path='/posts/add'
  render={({history}) => (
    <PostAdd history={history} />
  )}
/>

Крок 3: історія приймається як частина реквізиту в наступному компоненті, тому ви можете просто:

this.props.history.push('/');

Це було легко і по-справжньому потужно.


7

Це працює:

import { withRouter } from 'react-router-dom';

const SomeComponent = withRouter(({ history }) => (
    <div onClick={() => history.push('/path/some/where')}>
        some clickable element
    </div>); 
);

export default SomeComponent;

5

Моя відповідь подібна до Алекса . Я не впевнений, чому React-Router зробив це так непотрібно. Чому я повинен обертати свій компонент HoC просто для того, щоб отримати доступ до того, що по суті є глобальним?

У будь-якому випадку, якщо ви подивитеся на те, як вони реалізували <BrowserRouter>, це лише крихітна обгортка навколо історії .

Ми можемо витягнути цю історію, щоб ми могли імпортувати її з будь-якого місця. Підступність, однак, полягає в тому, що якщо ви робите візуалізацію на стороні сервера, і ви намагаєтеся здійснити importмодуль історії, він не працюватиме, оскільки використовує лише API-браузера. Але це нормально, оскільки ми зазвичай переспрямовуємо лише у відповідь на клацання чи якусь іншу подію клієнта. Таким чином, мабуть, добре це підробляти:

// history.js
if(__SERVER__) {
    module.exports = {};
} else {
    module.exports = require('history').createBrowserHistory();
}

За допомогою webpack ми можемо визначити кілька варіантів, щоб ми знали, у якому середовищі ми перебуваємо:

plugins: [
    new DefinePlugin({
        '__SERVER__': 'false',
        '__BROWSER__': 'true', // you really only need one of these, but I like to have both
    }),

А тепер можна

import history from './history';

Звідусіль. Він просто поверне порожній модуль на сервер.

Якщо ви не хочете використовувати ці магічні вар, вам доведеться просто потрапити requireв глобальний об'єкт, де це потрібно (всередині вашого обробника подій). importне працюватиме, оскільки працює лише на найвищому рівні.


6
чорт вони зробили це так складно.
Абхішек

4
Я цілком погодився з вами. це так складно лише для навігації
Thai Tran

5

Я думаю, що @rgommezz охоплює більшість випадків мінус один, що я думаю, що це досить важливо.

// history is already a dependency or React Router, but if don't have it then try npm install save-dev history

import createHistory from "history/createBrowserHistory"

// in your function then call add the below 
const history = createHistory();
// Use push, replace, and go to navigate around.
history.push("/home");

Це дозволяє мені написати просту службу з діями / викликами, які я можу зателефонувати, щоб зробити навігацію з будь-якого компонента, який я хочу, не роблячи багато HoC на своїх компонентах ...

Незрозуміло, чому раніше ніхто не забезпечував це рішення. Я сподіваюся, що це допомагає, і якщо ви бачите будь-яку проблему з цим, будь ласка, дайте мені знати.


4

Я тестую v4 вже кілька днів і .. Я люблю його поки що! Це просто має сенс через деякий час.

У мене також було те саме питання, і я виявив, що обробляти його так, як найкраще працював наступний (і може бути, як це призначено). Він використовує штат, потрійний оператор і <Redirect>.

У конструкторі ()

this.state = {
    redirectTo: null
} 
this.clickhandler = this.clickhandler.bind(this);

У візуалізації ()

render(){
    return (
        <div>
        { this.state.redirectTo ?
            <Redirect to={{ pathname: this.state.redirectTo }} /> : 
            (
             <div>
               ..
             <button onClick={ this.clickhandler } />
              ..
             </div>
             )
         }

У clickhandler ()

 this.setState({ redirectTo: '/path/some/where' });

Сподіваюся, це допомагає. Дай мені знати.


Чи є підводні камені за допомогою цього методу? У моєму проекті працює лише тоді, коли я встановлюю стан у конструкторі, звідти я можу перенаправляти на будь-яку сторінку, яку я хочу. Але коли я встановлюю стан на подію (реквізити змінилися, наприклад), я бачу метод візуалізації, викликаний новим станом, але перенаправлення не трапляється, я бачу ту саму сторінку
Дмитро Малугін

Проблема полягає в тому, що вона замінить історію, тому вам не вдасться відбити назад - так що в основному це не гарне рішення.
dannytenaglias

4

Я деякий час боровся з цим - щось таке просте, але таке складне, тому що ReactJS - це зовсім інший спосіб написання веб-додатків, він дуже чужий нам, старшому народові!

Я створив окремий компонент, щоб абстрагувати безлад:

// LinkButton.js

import React from "react";
import PropTypes from "prop-types";
import {Route} from 'react-router-dom';

export default class LinkButton extends React.Component {

    render() {
        return (
            <Route render={({history}) => (
                <button {...this.props}
                       onClick={() => {
                           history.push(this.props.to)
                       }}>
                    {this.props.children}
                </button>
            )}/>
        );
    }
}

LinkButton.propTypes = {
    to: PropTypes.string.isRequired
};

Потім додайте його до свого render()методу:

<LinkButton className="btn btn-primary" to="/location">
    Button Text
</LinkButton>

Я вважаю це рішення досить корисним. Я копіюю код. Дайте мені знати, що ви поклали його на github - я безпосередньо віднесу це до вас.
Абхінав Манчанда

3

Оскільки немає іншого способу впоратися з цим жахливим дизайном, я написав загальний компонент, який використовує підхід withRouter HOC . Приклад нижче - обгортання buttonелемента, але ви можете перейти на будь-який потрібний вам елемент:

import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';

const NavButton = (props) => (
  <Button onClick={() => props.history.push(props.to)}>
    {props.children}
  </Button>
);

NavButton.propTypes = {
  history: PropTypes.shape({
    push: PropTypes.func.isRequired
  }),
  to: PropTypes.string.isRequired
};

export default withRouter(NavButton);

Використання:

<NavButton to="/somewhere">Click me</NavButton>

3
this.props.history.push("/url")

Якщо ви не знайшли цю сторінку.props.history доступною у своєму компоненті, спробуйте це

import {withRouter} from 'react-router-dom'
export default withRouter(MyComponent)  

Дуже дякую!
QauseenMZ

1

Оскільки іноді я вважаю за краще перемикати маршрути за допомогою програми, а потім кнопками, це мінімальний робочий приклад, що для мене працює:

import { Component } from 'react'
import { BrowserRouter as Router, Link } from 'react-router-dom'

class App extends Component {
  constructor(props) {
    super(props)

    /** @type BrowserRouter */
    this.router = undefined
  }

  async handleSignFormSubmit() {
    await magic()
    this.router.history.push('/')
  }

  render() {
    return (
      <Router ref={ el => this.router = el }>
        <Link to="/signin">Sign in</Link>
        <Route path="/signin" exact={true} render={() => (
          <SignPage onFormSubmit={ this.handleSignFormSubmit } />
        )} />
      </Router>
    )
  }
}

0

Для тих із вас, хто потребує перенаправлення, перш ніж повністю ініціалізувати роутер за допомогою React Routerабо React Router Domви можете надати перенаправлення, просто перейшовши до об’єкта історії та натиснувши на нього новий стан у вашій конструкції app.js. Розглянемо наступне:

function getSubdomain(hostname) {
    let regexParse = new RegExp('[a-z\-0-9]{2,63}\.[a-z\.]{2,5}$');
    let urlParts = regexParse.exec(hostname);
    return hostname.replace(urlParts[0], '').slice(0, -1);
}

class App extends Component {

    constructor(props) {
        super(props);


        this.state = {
            hostState: true
        };

        if (getSubdomain(window.location.hostname).length > 0) {
            this.state.hostState = false;
            window.history.pushState('', '', './login');
        } else {
            console.log(getSubdomain(window.location.hostname));
        }

    }


    render() {
        return (

            <BrowserRouter>
                {this.state.hostState ? (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                        <Route path="/" component={PublicContainer}/>
                    </div>
                ) : (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                    </div>
                )

                }
            </BrowserRouter>)
    }


}

Тут ми хочемо змінити вихідні маршрути, залежні від субдомену, взаємодіючи з об’єктом історії, перш ніж компонент виведе, ми зможемо ефективно перенаправляти, залишаючи наші маршрути в такті.

window.history.pushState('', '', './login');
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.