Search code examples
reactjsbootstrap-4react-hooksreact-statereact-modal

Closing of modal while typing any value in it?


I want to implement update functionality in react. What I created is that I have an Update button, when it is clicked, a modal pops up with an input field to enter the updated value. But as soon as I type a single character, it closes and opens again (attached gif). Attached below is the code of React Component and gif.

import React , {useState} from'react';
import { Button,Form,Modal } from 'react-bootstrap';


const handleShowModal = (i) => {
    setModalShow(true);
}

const handleCloseModal = () => {
    setModalShow(false);
}

const handleCommentChange = (event) => {
    setModalInputComment(event.target.value);
}


function MyVerticallyCenteredModal(props) {

    return (
        <Modal
            {...props}
            size="lg"
            aria-labelledby="contained-modal-title-vcenter"
            centered
        >
        <Modal.Body>
          <Form>
              <div className="mb-3">
                <label  className="col-form-label">Username:</label>
                <input type="text" className="form-control" id="comment" />
              </div>
              <div className="mb-3">
                <label  className="col-form-label">Comment:</label>
                <textarea className="form-control" id="comment-text" value={modalInputComment} onChange={handleCommentChange}></textarea>
              </div>
          </Form>
        </Modal.Body>
        <Modal.Footer>
            <Button >Update</Button>
            <Button variant='secondary' onClick={handleCloseModal}>Close</Button>
        </Modal.Footer>
      </Modal>
    );
  }

  const [modalShow, setModalShow] = useState(false);
  
  const [modalInputComment, setModalInputComment] = useState();

  

return(
<>
    <div>
        {comments.map((item,key)=>(
            <div className="comment" key={key}>
                <h4>{item.username}</h4>
                <p>{item.text}</p>
                <Button variant="outline-primary btn-sm mx-3" onClick={() => handleShowModal(key)}>Update</Button>
            </div>

        ))}

        <MyVerticallyCenteredModal show={modalShow} />

    </div>

  </>
  )
 };

 export default CommentsList;

This is the comments array passed as props

This is the comments array passed as props

enter image description here

Above is a gif of the behaviour


Solution

  • Issue

    From what I can tell you are redeclaring the MyVerticallyCenteredModal within another component, so each time the component's state updates or is otherwise rerendered, a new MyVerticallyCenteredModal component is created. This will unmount the previous "instance" and mount a new "instance".

    Solution

    Move the MyVerticallyCenteredModal component definition outside any other components, pass all the appropriate props.

    function MyVerticallyCenteredModal({
      modalInputComment, // <-- destructure props
      handleCommentChange, // <-- destructure props
      ...props
    }) {
      return (
        <Modal
          {...props}
          size="lg"
          aria-labelledby="contained-modal-title-vcenter"
          centered
        >
          <Modal.Body>
            <Form>
              <div className="mb-3">
                <label className="col-form-label">Username:</label>
                <input type="text" className="form-control" id="comment" />
              </div>
              <div className="mb-3">
                <label className="col-form-label">Comment:</label>
                <textarea
                  className="form-control"
                  id="comment-text"
                  value={modalInputComment}
                  onChange={handleCommentChange}
                />
              </div>
            </Form>
          </Modal.Body>
          <Modal.Footer>
            <Button >Update</Button>
            <Button variant='secondary' onClick={handleCloseModal}>Close</Button>
          </Modal.Footer>
        </Modal>
      );
    }
    

    Component

      ...
    
      const handleShowModal = (i) => {
        setModalShow(true);
      }
    
      const handleCloseModal = () => {
        setModalShow(false);
      }
    
      const handleCommentChange = (event) => {
        setModalInputComment(event.target.value);
      }
    
      const [modalShow, setModalShow] = useState(false); 
      const [modalInputComment, setModalInputComment] = useState();
    
      return(
        <>
          <div>
            {comments.map((item,key)=>(
              <div className="comment" key={key}>
                <h4>{item.username}</h4>
                <p>{item.text}</p>
                <Button
                  variant="outline-primary btn-sm mx-3"
                  onClick={() => handleShowModal(key)}
                >
                  Update
                </Button>
              </div>
            ))}
    
            <MyVerticallyCenteredModal
              show={modalShow}
              modalInputComment={modalInputComment} // <-- pass props
              handleCommentChange={handleCommentChange} // <-- pass props
            />
          </div>
        </>
      );
    };