Как я могу программно перемещаться с помощью React Router?
С React Router я могу использовать элемент Link для создания ссылок, которые обрабатываются нативно React Router. Я вижу, что внутренне он вызывает this.context.transitionTo(...).
Я хочу выполнять перемещение. Не из ссылки, а из выпадающего списка (в качестве примера). Как я могу сделать это в коде? Что такое this.context?
Я видел миксин Navigation, но могу ли я сделать это без миксинов?
Программная навигация в React Router v6 достигается с помощью хука useNavigate для функциональных компонентов или хука useHistory в более старых версиях. Вы можете вызывать возвращаемую функцию с указанием пути назначения или объекта location для запуска навигации из любого компонента, включая выпадающие списки или другие интерактивные элементы.
Содержание
- Начало работы с программной навигацией
- Использование хука
useNavigate - Навигация из классовых компонентов
- Расширенные параметры навигации
- Обработка состояния навигации
- Миграция с v5 на v6
- Лучшие практики
Начало работы с программной навигацией
Программная навигация в React Router позволяет управлять навигацией из логики вашего приложения, а не полагаться исключительно на декларативные компоненты <Link>. Это особенно полезно для сценариев, когда навигация должна запускаться на основе пользовательских взаимодействий, таких как отправка форм, выбор в выпадающих списках или после завершения асинхронных операций.
В современном React Router v6 основным подходом является использование хука useNavigate, который предоставляет функцию, которую можно вызвать либо с указанием строкового пути, либо с объектом location для запуска навигации. Этот подход заменяет более старый компонент высшего порядка withRouter и миксин Navigation, упомянутые в вашем вопросе.
this.context, о котором вы упоминали, относится к API контекста React, который ранее использовался React Router для предоставления информации о маршрутизации компонентам. Однако в современных React-приложениях хуки стали предпочтительным подходом для доступа к контексту и другим возможностям React.
Использование хука useNavigate
Хук useNavigate - это стандартный способ обработки программной навигации в React Router v6. Вот как его реализовать:
import { useNavigate } from 'react-router-dom';
function MyComponent() {
const navigate = useNavigate();
const handleDropdownChange = (event) => {
const selectedValue = event.target.value;
navigate(selectedValue);
};
return (
<select onChange={handleDropdownChange}>
<option value="/home">Главная</option>
<option value="/about">О нас</option>
<option value="/contact">Контакты</option>
</select>
);
}
Навигация с параметрами
Вы также можете передавать параметры в функцию навигации для получения большего контроля:
const navigate = useNavigate();
// Навигация с опцией replace (не добавляется в историю)
navigate('/dashboard', { replace: true });
// Навигация с состоянием
navigate('/profile', {
state: { from: '/dashboard' },
replace: false
});
Относительная навигация
Для относительной навигации можно использовать опцию relative:
// Навигация на один уровень вверх
navigate('..', { relative: 'path' });
// Навигация в пределах того же маршрута, но с другими параметрами
navigate('..', { relative: 'path' });
Навигация из классовых компонентов
Хотя функциональные компоненты с хуками являются современным подходом, вам все еще может потребоваться обрабатывать навигацию в классовых компонентах. Вот несколько методов:
Использование контекста React Router
Вы можете напрямую получить доступ к контексту роутера в классовых компонентах:
import { useLocation, useNavigate } from 'react-router-dom';
class MyComponent extends React.Component {
static contextType = RouterContext;
handleNavigation = () => {
this.context.navigate('/new-path');
};
render() {
return <button onClick={this.handleNavigation}>Навигация</button>;
}
}
Шаблон компонента высшего порядка
Создайте компонент высшего порядка для внедрения навигации:
import { useNavigate } from 'react-router-dom';
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let navigate = useNavigate();
return <Component {...props} navigate={navigate} />;
}
return ComponentWithRouterProp;
}
// Использование в классовом компоненте
class MyComponent extends React.Component {
handleClick = () => {
this.props.navigate('/target');
};
render() {
return <button onClick={this.handleClick}>Навигация</button>;
}
}
export default withRouter(MyComponent);
Расширенные параметры навигации
Навигация с объектами location
Вместо простых строк вы можете передавать полные объекты location:
const location = {
pathname: '/users',
search: '?sort=asc',
hash: '#section1',
state: { from: '/dashboard' }
};
navigate(location);
Программная навигация с подтверждением
Вы можете добавлять диалоговые окна подтверждения перед навигацией:
const handleNavigate = () => {
if (window.confirm('Вы уверены, что хотите покинуть страницу?')) {
navigate('/new-page');
}
};
Навигация на основе условий
const navigate = useNavigate();
const handleSubmit = async () => {
const data = await submitForm();
if (data.success) {
navigate('/success');
} else {
navigate('/error');
}
};
Обработка состояния навигации
При программной навигации часто требуется передать состояние в целевой компонент:
// Исходный компонент
const navigate = useNavigate();
const handleClick = () => {
navigate('/profile', {
state: {
userId: '123',
timestamp: Date.now(),
referrer: '/dashboard'
}
});
};
// Целевой компонент
import { useLocation } from 'react-router-dom';
function ProfilePage() {
const location = useLocation();
const { state } = location;
// Доступ к переданному состоянию
const userId = state?.userId;
const referrer = state?.referrer;
return <div>Профиль пользователя {userId}</div>;
}
Сохранение состояния навигации
Обратите внимание, что состояние навигации не сохраняется при обновлении страницы браузера. Для данных, которые должны сохраняться, рассмотрите использование параметров URL или решения для управления состоянием.
Миграция с v5 на v6
Если вы мигрируете с React Router v5, вот ключевые изменения:
Руководство по миграции с v5 на v6
Хук истории в v5:
// React Router v5
import { useHistory } from 'react-router-dom';
function Component() {
const history = useHistory();
history.push('/new-path');
}
Хук Navigate в v6:
// React Router v6
import { useNavigate } from 'react-router-dom';
function Component() {
const navigate = useNavigate();
navigate('/new-path');
}
Ключевые отличия
- Имена хуков:
useHistory→useNavigate - Имена методов:
history.push()→navigate() - Параметры:
history.push(path, state)→navigate(path, { state }) - Относительная навигация: Новая опция
relativeв v6
Типовые шаблоны миграции
Замена withRouter:
// v5 - withRouter HOC
export default withRouter(MyComponent);
// v6 - Пользовательский HOC
import { useNavigate } from 'react-router-dom';
function withNavigation(Component) {
return function WrappedComponent(props) {
const navigate = useNavigate();
return <Component {...props} navigate={navigate} />;
};
}
Лучшие практики
1. Предпочитайте хуки вместо контекста
Современный React Router рекомендует использовать хуки вместо старого подхода с контекстом:
// Рекомендуется: использование хуков
const navigate = useNavigate();
// Не рекомендуется: прямой доступ к контексту
const context = useContext(RouterContext);
2. Обрабатывайте состояния загрузки при навигации
Предоставляйте обратную связь во время навигации:
function SubmitForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const navigate = useNavigate();
const handleSubmit = async () => {
setIsSubmitting(true);
try {
await submitData();
navigate('/success');
} catch (error) {
navigate('/error');
} finally {
setIsSubmitting(false);
}
};
return (
<button
onClick={handleSubmit}
disabled={isSubmitting}
>
{isSubmitting ? 'Отправка...' : 'Отправить'}
</button>
);
}
3. Используйте TypeScript для проверки типов
При использовании TypeScript вы можете получить лучшую безопасность типов:
import { useNavigate, NavigateFunction } from 'react-router-dom';
function Component() {
const navigate: NavigateFunction = useNavigate();
// TypeScript поможет отловить неверные пути
navigate('/valid-path'); // ✅
navigate('/invalid-path'); // ❌ Покажет ошибку типа
}
4. Избегайте жестко заданных путей
Используйте константы или конфигурацию для путей навигации:
const ROUTES = {
HOME: '/',
ABOUT: '/about',
DASHBOARD: '/dashboard',
PROFILE: '/profile',
};
function Component() {
const navigate = useNavigate();
const navigateToDashboard = () => {
navigate(ROUTES.DASHBOARD);
};
}
5. Обрабатывайте ошибки навигации
Реализуйте обработку ошибок для навигации:
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
function Component() {
const navigate = useNavigate();
const safeNavigate = (path: string) => {
try {
navigate(path);
} catch (error) {
toast.error('Ошибка навигации');
console.error('Ошибка навигации:', error);
}
};
}
Заключение
Программная навигация в React Router v6 проста в использовании с помощью хука useNavigate, который предоставляет чистый и современный подход для управления навигацией из логики вашего приложения. Хук возвращает функцию, которую можно вызвать либо с указанием строковых путей, либо с объектами location, что дает вам полный контроль над тем, как и когда происходит навигация.
Ключевые выводы включают:
- Используйте
useNavigate()для программной навигации в функциональных компонентах - Передавайте объекты location для сложных сценариев навигации с параметрами и состоянием
- Создавайте компоненты высшего порядка для классовых компонентов, которым нужен доступ к навигации
- Внимательно обрабатывайте состояние навигации, помня, что оно не сохраняется при обновлении страницы
- Следуйте современным шаблонам React и используйте TypeScript для лучшей безопасности типов
Старые подходы с прямым использованием контекста или миксинов, таких как Navigation, больше не рекомендуются в пользу подхода на основе хуков, который лучше соответствует современным практикам разработки React и обеспечивает лучшую производительность и безопасность типов.