Как реализовать модальное окно с помощью 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.
Вот и все! Я надеюсь, что это было полезно. Если у вас есть какие-либо вопросы, не стесняйтесь задавать. Спасибо за чтение!