Роутинг

Стероиды позволяют задать единое дерево роутов всего проекта, которое можно считать картой сайта.

В проекте, как правило, дерево задается в файле routes/index.ts, где корневым роутом root является главная страница (как правило, с адресом /), а ветви дерева задаются через items. Каждая страница описывается объектом с интерфейсом IRouteItem.

Задав такое дерево, вы получаете сразу несколько преимуществ:

  • Можно создавать ссылки по ID роута: <Link toRoute='root'>...</Link>'.
  • Можно выбрать ветвь дерева роутов и отрендерить по нему навигацию: <Nav items='profile'/>.
  • Лейблы ссылок и заголовки страниц будут браться из описанного дерева роутов.
  • Относительный путь до страниц – url, описывается только в дереве роутов, его легко изменять без рефакторинга проекта.
  • Разработчик может наглядно увидеть всю карту проекта, просто открыв дерево роутов.
  • У роутов можно указывать роли – roles, для ограничения доступа к странице по ролям пользователей.

Пример дерера роутов из трех страниц - главной и страниц профиля:

import IndexPage from './IndexPage';
import ProfileGeneral from './ProfileGeneral';
import ProfileSettings from './ProfileSettings';
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';

export const ROUTE_ROOT = 'root';
export const ROUTE_PROFILE = 'profile';
export const ROUTE_PROFILE_GENERAL = 'profile_general';
export const ROUTE_PROFILE_SETTINGS = 'profile_settings';

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    label: __('Главная страница'),
    component: IndexPage,
    roles: [null, 'user'], // могут видеть гости и авторизованные пользователи
    items: {
        [ROUTE_PROFILE]: {
            label: __('Профиль'),
            path: '/profile',
            redirectTo: true,
            roles: ['user'], // могут видеть только авторизованные пользователи
            items: {
                [ROUTE_PROFILE_GENERAL]: {
                    label: __('Основная информация'),
                    path: '/general', // указываем только часть пути, остальное добавится от родителя
                    component: ProfileGeneral,
                    // тут роли не указываем, они наследуются от родителя
                },
                [ROUTE_PROFILE_SETTINGS]: {
                    label: __('Настройки'),
                    path: '/settings',
                    component: ProfileSettings,
                },
            },
        },
    },
} as IRouteItem;

Относительные и абсолютные пути

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

Например:

// src/routes/index.ts
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';
import IndexPage from './IndexPage';
import LoginPage from './LoginPage';
import SignUpPage from './SignUpPage';

export const ROUTE_ROOT = 'root';

const roles = [null];

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    component: IndexPage,
    roles,
    items: {
        auth: {
            exact: true,
            path: '/auth',
            roles,
            items: {
                login: {
                    exact: true,
                    path: '/login', 
                    roles,
                    component: LoginPage,
                }, // LoginPage будет доступен по URL /auth/login
                signUp: {
                    exact: true,
                    path: '/sign-up',
                    roles,
                    component: SignUpPage
                } // SignUpPage будет доступен по URL /auth/sign-up
            }
        }
    }
} as IRouteItem;

Чтобы использовать дерево роутов с указанием абсолютных путей, нужно добавить в файле Application.tsx флаг alwaysAppendParentRoutePath для routerProps:

// src/Application.tsx
import useApplication from '@steroidsjs/core/hooks/useApplication';

export default function Application() {
    const {renderApplication} = useApplication({
        routerProps: {
            alwaysAppendParentRoutePath: false, // укажем флаг для использования абсолютных путей 
        },
        /* ... */
    });

    return renderApplication();
}

Тогда, для доступа к страницам авторизации и регистрации по тем же URL, что и в предыдущем примере будет необходимо исправить структуру дерева роутов на:

// src/routes/index.ts
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';
import IndexPage from './IndexPage';
import LoginPage from './LoginPage';
import SignUpPage from './SignUpPage';

export const ROUTE_ROOT = 'root';

const roles = [null];

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    component: IndexPage,
    roles,
    items: {
        auth: {
            exact: true,
            path: '/auth',
            roles,
            items: {
                login: {
                    exact: true,
                    path: '/auth/login', // Указываем абсолютный путь
                    roles,
                    component: LoginPage,
                }, // LoginPage будет доступен по URL /auth/login
                signUp: {
                    exact: true,
                    path: '/auth/sign-up', // Указываем абсолютный путь
                    roles,
                    component: SignUpPage
                } // SignUpPage будет доступен по URL /auth/sign-up
            }
        }
    }
} as IRouteItem;

Настройки роута

Параметры path, exact - передаются напрямую в React Router. Их описание можно посмотреть в официальной документации React Router.

Название и лейбл

Для каждого роута можно указать label и title. Приложение само может распоряжаться по какой логике использовать один или другой, но изначально смысл заложен такой - label используется для названия ссылок, а title - для заголовка страниц (а если не задан - используется label).

Отображение ссылок в дереве навигации

Бывают ситуации, когда не нужно отображать ссылку или кнопку в навигации для перехода на роут. Например, если нужно добавить роут для настроек профиля, но не добавлять его в навигацию. Для таких случаев удобно использовать параметр isNavVisible, в значении false.

Модифицируем дерево роутов так, чтобы путь /settings не был виден в навигации:

/* ... */

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    label: __('Главная страница'),
    component: IndexPage,
    roles: [null, 'user'],
    items: {
        [ROUTE_PROFILE]: {
            /* ... */
            items: {
                /* ... */
                [ROUTE_PROFILE_SETTINGS]: {
                    label: __('Настройки'),
                    path: '/settings',
                    component: ProfileSettings,
                    isNavVisible: false, // скроем роут из навигации
                },
            },
        },
    },
} as IRouteItem;

Редирект

Для автоматического редиректа роута на страницу, необходимо задать свойство redirectTo, в котором указывается path до страницы.

Например:

// src/routes/index.ts
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';
import IndexPage from './IndexPage';
import LoginPage from './LoginPage';
import SignUpPage from './SignUpPage';

export const ROUTE_ROOT = 'root';

const roles = [null];

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    component: IndexPage,
    roles,
    items: {
        auth: {
            exact: true,
            path: '/auth',
            roles,
            redirectTo: '/auth/login', // Указываем ссылку, на которую пользователь автоматически будет перенаправлен при попытке доступа к /auth
            items: {
                login: {
                    exact: true,
                    path: '/login', 
                    roles,
                    component: LoginPage,
                },
                signUp: {
                    exact: true,
                    path: '/sign-up',
                    roles,
                    component: SignUpPage
                }
            }
        }
    }
} as IRouteItem;

Часто бывает, что необходимо сделать редирект на дочернюю страницу раздела. Например, как в предыдущем примере, чтобы /auth перенаправлял на /auth/login, где login - одна из дочерних страниц ветви auth. В таком случае можно задать redirectTo в true, чтобы редирект был сделан на первую дочернюю страницу.

// src/routes/index.ts
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';
import IndexPage from './IndexPage';
import LoginPage from './LoginPage';
import SignUpPage from './SignUpPage';

export const ROUTE_ROOT = 'root';

const roles = [null];

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    component: IndexPage,
    roles,
    items: {
        auth: {
            exact: true,
            path: '/auth',
            roles,
            redirectTo: true, // Обратите внимание, не обязательно указывать ссылку, если необходимо перенаправить на первый роут из items
            items: {
                login: {
                    exact: true,
                    path: '/login', 
                    roles,
                    component: LoginPage,
                },
                signUp: {
                    exact: true,
                    path: '/sign-up',
                    roles,
                    component: SignUpPage
                }
            }
        }
    }
} as IRouteItem;