rgdzv
rgdzv

Reputation: 505

How to close a modal window clicking outside in React + Redux app?

Making an application (react + redux). It contains a few photos. When you click a photo you get a modal window with bigger photo and comments.

Code for ModalContainer (contains modal window itself):

class ModalContainer extends Component {
  state = {
    name: '',
    comment: '',
  }

  componentDidMount() {
    const { isOpen, closeModal } = this.props
    if (isOpen) {
      document.body.style.overflow = 'hidden'
    }
    document.addEventListener('click', closeModal)
  }

  componentWillUnmount() {
    const { closeModal } = this.props
    document.body.style.overflow = 'auto'
    document.removeEventListener('click', closeModal)
  }

  inputChange = (e) => {
    this.setState({
      [e.target.name]: e.target.value,
    })
  }

  putComment = (e) => {
    e.preventDefault()
    const { comment, name } = this.state
    const { photo } = this.props
    axios
      .post(
        `https://boiling-refuge-66454.herokuapp.com/images/${photo.id}/comments`,
        { name: name, comment: comment, date: Date.parse(String(new Date())) }
      )
      .then((res) => {
        console.log(res)
      })
    this.setState({
      name: '',
      comment: '',
    })
  }

  render() {
    const { name, comment } = this.state
    const { closeModal, photo } = this.props
    const comments = photo.comments
    return (
      <>
        <Modal
          onClick={closeModal}
          src={photo.url}
          comments={comments}
          name={name}
          comment={comment}
          onChange={this.inputChange}
          onSubmit={this.putComment}
        />
      </>
    )
  }
}

export default connect(
  ({ modal }) => ({
    photo: modal.photo,
    isOpen: modal.isOpen,
  }),
  { closeModal }
)(ModalContainer)

As you can see I have this code document.addEventListener('click', closeModal) inside componentDidMount() lifecycle method. Brackets contains action creator closeModal, which closes my modal. In that case it doesn't work correctly because it launches action creator even if I click inside my modal. So I can't add comment inside.

In this case, what is the proper way to close a modal window by clicking outside a window?

Upvotes: 1

Views: 1828

Answers (2)

strdr4605
strdr4605

Reputation: 4352

A common practice is to wrap Modal in an ModalOverlay,

style ModalOverlay to be full screen.

function onOverlayClick(e) {
  closeModal()
  e.stopPropagation()
}

function onModalClick(e) {
  // need to stop propagation to ModalOverlay onClick event
  e.stopPropagation()
}

return (
      <div className="full-screen" onClick={onOverlayClick}>
        <Modal
          onClick={onModalClick}
          src={photo.url}
          comments={comments}
          name={name}
          comment={comment}
          onChange={this.inputChange}
          onSubmit={this.putComment}
        />
      <div/>
    )

Upvotes: 1

Hagai Harari
Hagai Harari

Reputation: 2877

if Modal is a class component you can add ref to it (if it's a function component use fowardRef)

<Modal ref={modalNode => (this.modalNode = modalNode)}

and adapt your eventListener

handleClick = e => !this.modalNode.contains(e.target) && closeModal();

 componentDidMount() {
    const { isOpen, closeModal } = this.props
    if (isOpen) {
      document.body.style.overflow = 'hidden'
    }
    document.addEventListener('click', this.handleClick)
  }

Upvotes: 2

Related Questions