#javascript #reactjs #redux
#javascript #reactjs #переопределение
Вопрос:
Создание простого приложения с использованием React и Redux.
Суть в том, чтобы получить фотографии с сервера и показать их. Если вы нажмете на фотографию, вы получите модальное окно с увеличенной фотографией и комментариями. Я использую Portal в своем модальном компоненте.
Форма кода ModalContainer
import React from 'react'
import { closeModal } from '../redux/actions/actions'
import Modal from '../components/modal/Modal'
import axios from 'axios'
import { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useEffect } from 'react'
const ModalContainer = () => {
const [user, setUser] = useState({
name: '',
comment: '',
})
const { photo, isOpen } = useSelector(({ modal }) => modal);
const dispatch = useDispatch();
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden'
}
return () => {
document.body.style.overflow = 'auto'
}
}, []);
const handleChange = ({ target: { value, name } }) => {
setUser({
...user,
[name]: value
})
}
const modalClose = () => {
dispatch(closeModal())
}
const onOverlayClick = (e) => {
dispatch(closeModal())
e.stopPropagation()
}
const onModalClick = (e) => {
e.stopPropagation()
}
const pushComment = (e) => {
e.preventDefault()
axios
.post(
`https://boiling-refuge-66454.herokuapp.com/images/${photo.id}/comments`,
{ name: user.name, comment: user.comment, date: Date.parse(String(new Date())) }
)
.then((res) => {
console.log(res)
})
setUser({
name: '',
comment: '',
})
}
return (
<Modal
onClick={modalClose}
onLayoutClick={onOverlayClick}
onModalClick={onModalClick}
src={photo.url}
comments={photo.comments}
name={user.name}
comment={user.comment}
onChange={handleChange}
onSubmit={pushComment}
/>
)
}
export default ModalContainer
Код для портала
import ReactDOM from 'react-dom';
import { useEffect } from 'react';
const Portal = ({ children }) => {
const el = document.createElement('div');
useEffect(() => {
document.body.appendChild(el);
return () => {
document.body.removeChild(el);
}
}, [])
return ReactDOM.createPortal(children, el);
}
export default Portal
Код для модального
import React, { Fragment } from 'react'
import './Modal.scss'
import close from '../../images/close.png'
import Input from '../input/Input'
import Button from '../button/Button'
import PropTypes from 'prop-types'
import Portal from '../portal/Portal'
const Modal = ({
onClick,
onChange,
onSubmit,
src,
comments,
name,
comment,
onModalClick,
onLayoutClick,
}) => {
return (
<Portal>
<div className="modal__layout" onClick={onLayoutClick}>
<div className="modal__window" onClick={onModalClick}>
<div className="modal__content">
<div className="modal__item">
<img src={src} alt={src} />
<div className="modal__comments">
<div className="modal__comment">
{comments.map((comment) => {
return (
<Fragment key={comment.id}>
<p>{new Date(comment.date).toLocaleDateString()}</p>
<p>{comment.text}</p>
</Fragment>
)
})}
</div>
</div>
</div>
<form onSubmit={onSubmit}>
<Input
name="name"
type="text"
value={name}
placeholder="Ваше имя"
onChange={onChange}
/>
<Input
name="comment"
type="text"
value={comment}
placeholder="Ваш комментарий"
onChange={onChange}
/>
<Button>Оставить комментарий</Button>
</form>
<img className="close" src={close} alt="close" onClick={onClick} />
</div>
</div>
</div>
</Portal>
)
}
Modal.propTypes = {
onClick: PropTypes.func,
onModalClick: PropTypes.func,
src: PropTypes.string,
comments: PropTypes.array,
onChange: PropTypes.func,
name: PropTypes.string,
comment: PropTypes.string,
onSubmit: PropTypes.func,
onLayoutClick: PropTypes.func,
}
Modal.defaultProps = {
onClick: () => {},
onModalClick: () => {},
src: '',
comments: [],
onChange: () => {},
name: '',
comment: '',
onSubmit: () => {},
onLayoutClick: () => {},
}
export default Modal
Проблема в том, что когда я открываю модальное окно с увеличенной фотографией и комментариями и пытаюсь заполнить входные данные или нажать кнопку без текста во входных данных, чтобы отправить комментарий на сервер, модальное окно закрывается и вообще не реагирует. Но без компонента портала он работает отлично. В чем проблема?
Комментарии:
1. Что вы имеете в виду, говоря, что вообще не реагирует?
2. Во-первых, это плохая практика игры с DOM в приложении react
3. @simbathesailor, я имею в виду, что вы не можете открыть модальное окно
4. @Rajesh, какой-нибудь совет тогда?
Ответ №1:
Вы делаете что-то вроде этого. Дайте мне знать, если это приведет к улучшению результатов.
// Code form ModalContainer
<Modal
onClick={modalClose}
onLayoutClick={onOverlayClick}
onModalClick={onModalClick}
src={photo.url}
comments={photo.comments}
name={user.name}
comment={user.comment}
onChange={handleChange}
onSubmit={pushComment}
isOpen={isOpen}
/>
// Modal code
const Modal = ({
onClick,
onChange,
onSubmit,
src,
comments,
name,
comment,
onModalClick,
onLayoutClick,
isOpen
}) => {
return (
<Portal isOpen={isOpen}>
<div className="modal__layout" onClick={onLayoutClick}>
<div className="modal__window" onClick={onModalClick}>
<div className="modal__content">
<div className="modal__item">
<img src={src} alt={src} />
<div className="modal__comments">
<div className="modal__comment">
{comments.map((comment) => {
return (
<Fragment key={comment.id}>
<p>{new Date(comment.date).toLocaleDateString()}</p>
<p>{comment.text}</p>
</Fragment>
)
})}
</div>
</div>
</div>
<form onSubmit={onSubmit}>
<Input
name="name"
type="text"
value={name}
placeholder="Ваше имя"
onChange={onChange}
/>
<Input
name="comment"
type="text"
value={comment}
placeholder="Ваш комментарий"
onChange={onChange}
/>
<Button>Оставить комментарий</Button>
</form>
<img className="close" src={close} alt="close" onClick={onClick} />
</div>
</div>
</div>
</Portal>
)
}
Modal.propTypes = {
onClick: PropTypes.func,
onModalClick: PropTypes.func,
src: PropTypes.string,
comments: PropTypes.array,
onChange: PropTypes.func,
name: PropTypes.string,
comment: PropTypes.string,
onSubmit: PropTypes.func,
onLayoutClick: PropTypes.func,
}
// Portal Code
import ReactDOM from 'react-dom';
import { useEffect, useState } from 'react';
const Portal = ({ children, isOpen }) => {
const [elem, setElem] = useState(null)
useEffect(() => {
const el = document.createElement('div');
document.body.appendChild(el);
setElem(el)
return () => {
document.body.removeChild(el);
}
}, [])
// useEffect(() => {
// if(isOpen) {
// document.body.appendChild(el);
// }
// return () => {
// document.body.removeChild(el);
// }
// }, [isOpen])
if(!el || !isOpen) return null
if(el amp;amp; isOpen) return ReactDOM.createPortal(children, el);
}
export default Portal