Wątek przeniesiony 2023-08-01 11:41 z JavaScript przez Riddle.

Jak poprawnie napisać okno dialogowe?

0

Chce stworzyc Modal ktory po kliknieciu poza jego obszar zamyka sie ale jego zawartosc zostaje jedynie ukryta oraz po kliknieciu esc znika on calkowicie z kodu.

Zrobilem tak:

export const DialogModalTester = ({ editor }: ImageButtonProps) => {
	const [isOpened, setIsOpened] = useState(false);
	const [isVisible, setIsVisible] = useState(false);

	let onClick = () => {
		setIsOpened(true);
		setIsVisible(true);
	};
	return (
		<div>
			<button onClick={onClick}>Open "dialog" modal</button>
			{isOpened && (
				<ImageModal
					editor={editor}
					isOpened={isOpened}
					setIsOpened={setIsOpened}
					isVisible={isVisible}
					setIsVisible={setIsVisible}
					uploadOptions={{ handler: defaultImageUploadHandler }}
				/>
			)}
		</div>
	);
};

Powyzej mam state isOpened ktory poczatkowo jest false czyli nie ma modala, a po kliknieciu w button zminia sie na true i pojawia sie modal oraz state isVisible ktory ma kontrolowac czy modal jest widoczny czy nie. Przekazuje oba state i settery do ImageModal ktory wyglada tak:

return (
  <div>
      <DialogModal
          isVisible={isVisible}
          onOutsideClick={() => setIsVisible(false)}
          onClose={() => setIsOpened(false)}
      >
          <div id="image-modal">
              <div className="upload-container">
                  <div className="header">
                      <h1>Image</h1>
                      <button className="close-btn" onClick={() => setIsOpened(false)}>
                          <img src={CloseIcon}></img>
                      </button>
                  </div>

                  {uploadStatus !== "uploadSuccess" && uploadStatus !== "goodLink" ? (
                      <div
                          className={
                              `drag-area` + `${isDragActive ? " drag-active" : ""}`
                          }
                          onDragOver={onDragOver}
                          onDragLeave={onDragLeave}
                          onDrop={onDrop}
                      >
                          <div className="icon">
                              <ImagesIcon />
                          </div>

                          <span className="drag-and-drop">
                              {isDragActive ? "Release to Upload," : "Drag & Drop,"}
                          </span>
                          <span className="paste-image">paste an image, </span>
                          <button onClick={onClickPasteUrl} className="paste-url">
                              paste link,{" "}
                          </button>
                          <span className="browse">
                              or{" "}
                              <span
                                  onClick={() => browseInputRef.current.click()}
                                  className="browse-btn"
                              >
                                  browse
                              </span>
                          </span>
                          <input
                              ref={browseInputRef}
                              type="file"
                              onChange={onFileSelection}
                              hidden
                          ></input>
                          <span className="support">Supports: JPEG, JPG, PNG</span>
                      </div>
                  ) : (
                      <div className="image-preview">
                          <img src={imageUrl} alt="Image not found"></img>
                      </div>
                  )}
              </div>

              {uploadStatus && <UploadNotice />}

              <div>
                  <label htmlFor="link-editor-href-input" className="s-label mb4">
                      {_t("link_editor.href_label")}
                  </label>
                  <input
                      ref={linkInputRef}
                      value={imageUrl}
                      placeholder="Paste image URL here"
                      onInput={(e) =>
                          setAndValidateUrl((e.target as HTMLInputElement).value)
                      }
                      id="link-editor-href-input"
                      className="s-input"
                      type="text"
                      name="href"
                      aria-describedby="link-editor-href-error"
                  />
                  <p
                      id="link-editor-href-error"
                      className="s-input-message mt4 d-none js-link-editor-href-error"
                  ></p>
              </div>

              <div className="d-flex py8 jc-space-between ai-center sm:fd-column sm:ai-start sm:g16">
                  <div>
                      <button
                          className="s-btn s-btn__primary ws-nowrap mr8 js-add-image"
                          type="button"
                          onClick={onSubmit}
                          disabled={isDisabled}
                      >
                          Add image
                      </button>
                      <button
                          className="s-btn ws-nowrap js-cancel-button"
                          type="button"
                          onClick={onClose}
                      >
                          Cancel
                      </button>
                  </div>
              </div>
          </div>
      </DialogModal>
  </div>
);

I co wazniejsze tak wyglada moj podstawowy modal DialogModal:

const DialogModal = ({
	isVisible,
	onClose,
	children,
	onOutsideClick,
}: Props) => {
	const ref = useRef<HTMLDialogElement>(null);

	useEffect(() => {
		if (isVisible) {
			ref.current?.showModal();
			document.body.classList.add("modal-open"); // prevent bg scroll
		} else {
			ref.current?.close();
			document.body.classList.remove("modal-open");
		}
	}, [isVisible]);

	return (
		<div
			className="modal-overlay"
			onClick={(e) => {
				ref.current &&
					!isClickInsideRectangle(e, ref.current) &&
					onOutsideClick();
			}}
		>
			<dialog className="modal-dialog" ref={ref} onCancel={onClose}>
				{children}
			</dialog>
		</div>
	);
};

Uzywam useEffect zeby w momencie w ktorym wartosc isVisible sie zmieni moc pokazac/ukryc modal

Problem:

  1. Po kliknieciu naprzycisk do pokazania modala, akcja useEffect wykonywana jest dwukrtonie i przy pierwszym wykonaniu jest OK i pokazuje sie modal ale przy drugim modal jest juz widoczny wiec showModal zwraca blad. Dlaczego dwa razy wywolywany jest ten efekt?
  2. Nawet jak uda sie rozwiazac 1, wydaje mi sie ze dalej nie bedzie to dzialalo jak nalezy bo jesli klikne na zewnatrz modala i setVisible sie ustawi na false, to modal sie schowa ale chyba strace tez jego zawartosc bo wygeneruje sie on od nowa wewnatrz DialogModalTester.
0
Kokos123 napisał(a):

Problem:

  1. Po kliknieciu naprzycisk do pokazania modala, akcja useEffect wykonywana jest dwukrtonie i przy pierwszym wykonaniu jest OK i pokazuje sie modal ale przy drugim modal jest juz widoczny wiec showModal zwraca blad. Dlaczego dwa razy wywolywany jest ten efekt?

React w strict mode celowo renderuje komponenty dwa razy, żeby wykryć potencjalne błędy.
https://react.dev/reference/react/StrictMode
A twoim błędem jest to, że nie dałeś metody cleanup, w którym w tym przypadku byś chował modala, zanim otworzy się

document.body.classList.add("modal-open"); // prevent bg scroll

To jest hak, takie bezpośrednie włażenie do domu. Lepiej by było, gdybyś gdzieś na górze apki wykrywał, czy jest dialog otwarty czy nie, i renderował zawartość w JSX z klasą modal-open albo nie.

0
LukeJL napisał(a):
Kokos123 napisał(a):

Problem:

  1. Po kliknieciu naprzycisk do pokazania modala, akcja useEffect wykonywana jest dwukrtonie i przy pierwszym wykonaniu jest OK i pokazuje sie modal ale przy drugim modal jest juz widoczny wiec showModal zwraca blad. Dlaczego dwa razy wywolywany jest ten efekt?

React w strict mode celowo renderuje komponenty dwa razy, żeby wykryć potencjalne błędy.
https://react.dev/reference/react/StrictMode
A twoim błędem jest to, że nie dałeś metody cleanup, w którym w tym przypadku byś chował modala, zanim otworzy się

document.body.classList.add("modal-open"); // prevent bg scroll

To jest hak, takie bezpośrednie włażenie do domu. Lepiej by było, gdybyś gdzieś na górze apki wykrywał, czy jest dialog otwarty czy nie, i renderował zawartość w JSX z klasą modal-open albo nie.

Zrobilem

if (isVisible) {
    ref.current?.close();
    ref.current?.showModal();

I dziala, dzieki :) I chowanie/usuwanie modala dziala tez jak nalezy, wbrew moim obawom :P Pojawil sie inny niespodziewany problem - w momencie w ktorym klikam browse, modal sie chowa :( Debugujac zauwazylem ze w metodzie isClickInsideRectangle, pozycja inputa jest 0 w kazdym kierunku. Jak to naprawic zeby modal pozostal otwarty przy otwieraniu inputa, wybieraniu pliku i anulowaniu inputa?

1 użytkowników online, w tym zalogowanych: 0, gości: 1