Как реализовать модальное окно с помощью React Router v6
Привет! Я искал, как реализовать Modal в React Router v6, но, к сожалению, полученные результаты не соответствовали моим потребностям. В обучающих блогах, с которыми я столкнулся, использовались JSX Routes, а я использую createBrowserRouter для управления своим стеком истории. После некоторых поисков и попыток заставить его работать, я наконец заставил его работать.
Если вы хотите создать приведенный выше пример GIF, но в React V6 и используете createBrowserRouter, то это руководство для вас.
Вот как я это сделал.
В приведенном ниже руководстве основное внимание будет уделено реализации modal, у которого нет навигационной панели, как на изображении выше.
Начало
Перво-наперво, вам нужно создать приложение react и установить react-router-dom и запустить npm install для запуска.
Давайте начнем со структуры папок. Просто скопируйте расположение моих файлов и папок, приведенное ниже:
/src
/components
Modal.js
/data
dummy-data.js
/pages
Gallery.jsx
App.jsx
dummy-data.js
export const images = [
{
id: 1,
thumbnail:
'https://images.unsplash.com/photo-1682685797886-79020b7462a4?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fHx8',
fullSize:
'https://images.unsplash.com/photo-1682685797886-79020b7462a4?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
details: 'Details about Image 1',
},
{
id: 2,
fullSize:
'https://images.unsplash.com/photo-1706028024882-0b972506d02d?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
thumbnail:
'https://images.unsplash.com/photo-1706028024882-0b972506d02d?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzfHx8ZW58MHx8fHx8',
details: 'Details about Image 2',
},
];
dummy-data.js содержит объект массива, который будет использоваться в качестве фиктивных данных. id будет уникальным идентификатором нашего изображения, который будет использоваться позже для получения подробной информации об изображении.
Modal.jsx
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { images } from '../data/dummy-data';
const Modal = () => {
const { id: imageId } = useParams();
const navigate = useNavigate();
const [imageData, setImageData] = useState({});
useEffect(() => {
const image = images.find(({ id }) => imageId == id);
setImageData(image);
}, [imageId]);
const handleOnClose = () => {
navigate('/');
};
return (
<>
{imageData && (
<div className="modal">
<div className="modal-content">
<img src={imageData.fullSize} alt="Full Size" />
<p>{imageData.details}</p>
<button onClick={handleOnClose}>Close</button>
</div>
</div>
)}
</>
);
};
export default Modal;
Modal.jsx — это функциональный компонент, который будет использоваться в качестве всплывающего окна для просмотра деталей конкретного изображения.
Объявления переменных:
imageId: извлекает идентификатор из маршрута с помощью useParams(). Это уникальный идентификатор изображения, отображаемого в модальном окне.
navigate Предоставляет функцию для навигации между страницами с помощью useNavigate().
Управление состоянием:
imageData представляет состояние хранения информации о выбранном изображении.
useEffect используется для получения сведений об изображении при монтировании компонента или изменении imageId. Он находит соответствующее изображение в объекте массива images (импортированном из фиктивных данных).
Закрыть модальную функцию:
handleOnClose определяет функцию для закрытия модели путем возврата к корневому пути ('/) с помощью функции navigate.
Модальный рендеринг:
Компонент отображает модальное окно только в том случае, если imageData правдива (т. е. изображение найдено). Внутри модального окна отображается полноразмерное изображение, дополнительные сведения и кнопка закрытия.
Gallery.jsx
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { images } from '../data/dummy-data';
import Modal from '../components/Modal';
const Gallery = () => {
const navigate = useNavigate();
const viewImage = (image) => {
const id = image.id;
navigate('/view/' + id);
};
return (
<div className="gallery">
{images.map((image, index) => (
<button
key={image.id}
className="gallery-item"
onClick={() => viewImage(image)}
>
<img src={image.thumbnail} alt={`Thumbnail ${index + 1}`} />
</button>
))}
<Modal />
</div>
);
};
export default Gallery;
Gallery.jsx отвечает за отображение галереи изображений с предварительным просмотром миниатюр. Внутри компонента он сопоставляет объект массива изображений из фиктивных данных. Каждая кнопка имеет обработчик события нажатия (onClick), который вызывает функцию viewImage с соответствующим изображением.
Функция viewImage принимает параметр объекта изображения на основе щелчка по миниатюре и извлекает свойство id из объекта изображения. Затем он переходит к маршруту view/:id.
Компонент Modal отображается в конце компонента Gallery. Он включен для обеспечения модальной функциональности для просмотра подробной информации о выбранном изображении.
App.jsx
import React from 'react';
import Gallery from './pages/gallery';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter([
{
path: '/',
element: <Gallery />,
children: [
{
path: 'view/:id',
element: null,
},
],
},
]);
function App() {
return (
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
}
export default App;
createBrowserRouter — рекомендуемый маршрутизатор для всех веб-проектов React Router. Он использует API истории DOM для обновления URL-адреса и управления стеком истории.
Основной маршрутизатор для приведенного выше кода указан с помощью path: '/' и настроен на отрисовку компонента Gallery.
Кроме того, существует дочерний маршрут, определенный с помощью path: 'view/:id', но элементу, связанному с ним, присвоено значение null.
Компонент RouterProvider используется для предоставления экземпляра маршрутизатора (router) всему дереву компонентов React. Это крайне важно для включения функции маршрутизации.
Краткое объяснение
У нас есть родительский маршрут index, и у него есть дочерний маршрут view/:id, который отображает нулевой элемент. Если мы перейдем к этому маршруту, родительский элемент сохранит свою текущую позицию. Причина этого в том, что у нас нет <Outlet /> для отображения дочерних элементов родительского маршрута. Таким образом, он просто останется в том месте, где мы запускаем навигацию. Причина, по которой отображается Modal, заключается в том, что у нас есть useEffect, который срабатывает при изменении gallery/:id. Он сработает, только если мы щелкнем по миниатюрам, которые запускают обновление URL.
Вот и все! Я надеюсь, что это было полезно. Если у вас есть какие-либо вопросы, не стесняйтесь задавать. Спасибо за чтение!