Wątek przeniesiony 2023-07-27 09:09 z JavaScript przez Riddle.

Jak wyrenderowac element poprzez klikniecie na przycisk uzywajac portalu

0

Mam moja aplikacje React w ktorej istnieje przycisk z nastepujaca akcja:

let linkEditor = new LinkEditor({
    view: view,
    href: "",
    title: "",
    validateLink: null,
});

linkEditor.render();
showModal(document.querySelector("#modal-base") as HTMLElement);

gdzie LinkEditor uzyaw portalu jak nizej:

export class LinkEditor extends React.Component {
	hrefInput: HTMLInputElement | null = null;
	textInput: HTMLInputElement | null = null;
	saveBtn: HTMLButtonElement | null = null;
	hrefError: HTMLParagraphElement | null = null;
	view: EditorView | null = null;

	title: string = "";
	href: string = "";
	validateLink: any;

	constructor(props: Props) {
		super(props);
		this.validateLink = props.validateLink;
		this.view = props.view;
		this.title = props.title;
		this.href = props.href;
	}

	render(): React.ReactNode {
		let editor = (
			<form className="mt6 bt bb bc-black-400 js-link-editor">
				<div className="d-flex fd-column gsy gs8 p12">
					<div className="flex--item">
						<label htmlFor="link-editor-href-input" className="s-label mb4">
							{_t("link_editor.href_label")}
						</label>
						<input
							id="link-editor-href-input"
							className="s-input js-link-editor-href"
							type="text"
							name="href"
							value={this.href}
							aria-describedby="link-editor-href-error"
							ref={(c) => (this.hrefInput = c)}
						/>
						<p
							id="link-editor-href-error"
							className="s-input-message mt4 d-none js-link-editor-href-error"
							ref={(c) => (this.hrefError = c)}
						></p>
					</div>

					<div className="flex--item">
						<label htmlFor="link-editor-text-input" className="s-label mb4">
							{_t("link_editor.text_label")}
						</label>
						<input
							id="link-text-href-input"
							className="s-input js-link-editor-text"
							type="text"
							value={this.title}
							name="text"
							ref={(c) => (this.textInput = c)}
						/>
					</div>

					<div className="flex--item">
						<button
							className="s-btn s-btn__primary js-link-editor-save-btn"
							type="submit"
							disabled
							ref={(c) => (this.saveBtn = c)}
						>
							${_t("link_editor.save_button")}
						</button>
						<button className="s-btn" type="reset">
							${_t("link_editor.cancel_button")}
						</button>
					</div>
				</div>
			</form>
		);

		return ReactDOM.createPortal(
			editor,
			document.getElementById("link-editor")!
		);
	}

Myślałem ze jak wywołam render() to formularz z klasy LinkEditor zostanie wyrenderowany wewnątrz już istniejącego divu z id link-editor (jak wskazuje portal i najlepiej bez re-renderowania całej aplikacji) ale nic takiego się nie dzieje. Co powinienem zmienić, żeby przed wywolaniem showModal, wygenerować ta zawartość z linkEditora zeby po prostu moc ja wyswietlic w moim modalu?

2
Kokos123 napisał(a):

Myslalem ze jak wywolam render() to formularz z klasy LinkEditor zostanie wyrenderowany wewnatrz juz istniejacego divu z id link-editor

Gdzie masz ten div o id link-editor? W kodzie, w którym wrzuciłeś, nie widać, żeby było coś takiego.

let linkEditor = new LinkEditor({
	view: view,
	href: "",
	title: "",
	validateLink: null,
});

No ale czemu tworzysz ręcznie instancję komponentu React przez new LinkEditor? Dla mnie to wygląda na jakieś błędne użycie Reacta (ew. jakaś hipsterska sztuczka, której nie znam). Zwykle to React tworzy sobie instancje klas i nimi zarządza.

linkEditor.render();

Natomiast metoda render w komponentach reactowych wcale nie nic nie renderuje naprawdę, to trochę myląca nazwa, bo ona jedynie zwraca to, jak ma komponent wyglądać (podejście deklaratywne). Natomiast za prawdziwy rendering odpowiedzialny jest React. I robi się to inaczej:
https://react.dev/reference/react-dom/client

Swoją drogą polecam komponenty funkcyjne i hooki zamiast komponentów klasowych. Może łatwiej będzie zrozumieć założenia na funkcjach (które bardziej pasują do modelu Reacta) zamiast na klasach.

0

Po prostu przeczytaj dokumentację, nie zajmie Ci to dłużej niż 30 minut: https://react.dev/learn

0

Sprawa wyglada tak ze mam WYSIWYG edytor ktory ma przycisk po ktorego wcisnieciu chce wyswietlic modal z edytorem linka (z href i tytulem do wyswietlenia). Stad mam klase LinkEditor. Kontener link-editor jest zdefiniowany poza kontenerem w ktorym jest ten przycisk bo w innym wypadku modal nie wyswitli sie poprawnie na calej stronie w zwiazku z stacking context itp. Wiec uzywa Portalu. Jesli klikam na przycisk to ma sie otworzyc pusty edytor (bo dopiero chce wstawic link) a jak klikam na juz wstawiony link ale chce go edytowac to do tego mam inny przycisk i on otwiera ten sam LinkEditor ale juz z konretnymi wartosciami stad mam klase ktora w konstruktorze ustawia te wartosci.

Rozwiazalem moj problem poprzez nastepujacy kod:

	let modal = linkEditor.render();
	createRoot(document.querySelector("#link-editor") as HTMLElement).render(
		modal
	);

Dziala, pytanie czy nie robie czegos zle i na przeciw temu jak powinien dzialac React?

0
Kokos123 napisał(a):

Sprawa wyglada tak ze mam WYSIWYG edytor ktory ma przycisk po ktorego wcisnieciu chce wyswietlic modal z edytorem linka (z href i tytulem do wyswietlenia). Stad mam klase LinkEditor. Kontener link-editor jest zdefiniowany poza kontenerem w ktorym jest ten przycisk bo w innym wypadku modal nie wyswitli sie poprawnie na calej stronie w zwiazku z stacking context itp. Wiec uzywa Portalu. Jesli klikam na przycisk to ma sie otworzyc pusty edytor (bo dopiero chce wstawic link) a jak klikam na juz wstawiony link ale chce go edytowac to do tego mam inny przycisk i on otwiera ten sam LinkEditor ale juz z konretnymi wartosciami stad mam klase ktora w konstruktorze ustawia te wartosci.

Rozwiazalem moj problem poprzez nastepujacy kod:

	let modal = linkEditor.render();
	createRoot(document.querySelector("#link-editor") as HTMLElement).render(
		modal
	);

Dziala, pytanie czy nie robie czegos zle i na przeciw temu jak powinien dzialac React?

Powinieneś zrobić

const root = createRoot(document.querySelector("#link-editor") as HTMLElement);
root.render(<LinkEditor/>);

Nie wołaj .render() na komponentach samemu.

Po prostu przeczytaj dokumentację: https://react.dev/learn

0

@Riddle: ale jak wtedy podac parametry do konstruktora LinkEditor? Nie moge zrobic <LinkEditor href="..."/> Ja generalnie juz na samym poczatku wolam

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
      <div>
          <App />
      </div>
  </React.StrictMode>
);

I teraz po prostu chce dorenderowac ten jeden LinkEditor we wskazanym divie wiec wołam jeszcze raz createRoot().render() tylko na innym divie. Czy to jest OK?

0
Kokos123 napisał(a):

@Riddle: ale jak wtedy podac parametry do konstruktora LinkEditor? Nie moge zrobic <LinkEditor href="..."/> Ja generalnie juz na samym poczatku wolam

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
      <div>
          <App />
      </div>
  </React.StrictMode>
);

I teraz po prostu chce dorenderowac ten jeden LinkEditor we wskazanym divie wiec wołam jeszcze raz createRoot().render() tylko na innym divie. Czy to jest OK?

Nie.

Jak chcesz dodać ten komponent, to zrób tak:

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
      <div>
          <App />
          <LinkEditor href="something"/>
      </div>
  </React.StrictMode>
);
0
Riddle napisał(a):
Kokos123 napisał(a):

@Riddle: ale jak wtedy podac parametry do konstruktora LinkEditor? Nie moge zrobic <LinkEditor href="..."/> Ja generalnie juz na samym poczatku wolam

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
      <div>
          <App />
      </div>
  </React.StrictMode>
);

I teraz po prostu chce dorenderowac ten jeden LinkEditor we wskazanym divie wiec wołam jeszcze raz createRoot().render() tylko na innym divie. Czy to jest OK?

Nie.

Jak chcesz dodać ten komponent, to zrób tak:

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
      <div>
          <App />
          <LinkEditor href="something"/>
      </div>
  </React.StrictMode>
);

Ale div do ktorego ma powedrowac LinkEditor znajduje sie w App i href bedzie za kazdym razem inny.

  1. Mam diva ktory ma byc kotenerem na wszystkie modale
  2. W App mam komponent MenuButton ktory ma wsadzic zawartosc LinkEditora w ten modal kontener i go wyswietlic
  3. href moze byc niepusty bo moge juz miec link i kliknac Edit i tez ma sie otworzyc modal tylko z tym hrefem.

Takze nie widze jak mialoby to dzialac w rozwiazaiu ktore podales.

0

@Kokos123: Pytanie zasadnicze, przeczytałeś dokumentację? https://react.dev/reference/react-dom/createPortal

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