React js. Pare pytań ogólnych do doświadczoncyh programistów reacta (manipulacja DOM)

0

Witam

Mianowicie zacząłem się uczyć reacta.js w praktyce tzn robiąc w nim strony internetowe. Ucze sie głównie z w3school oraz turturiali na yt. I o ile
nie mam żadnych problemów z robieniem statycznych stron. Problem pojawia się kiedy trzeba manipulować DOM w reacie.
Jeśli bym robił stronę bez reacta.js to zwyczajnie zadziałał bym na jQuerry i javascripcie i w ten sposób w dowolny sposób manipulował DOM-em.
Tylko że wszędzie jak mantre wszyscy powtarzają że nie wolno manipulować DOM w reacie za pomoca JS. Należy zamiast tego używać "state-ow"
i "refow". No i problem jest taki że o ile proste manipulacje dam rady obsłużyć za pomocą "refow" i "statow" to już kompletnie gubie się jeśli muszę zrobić jakaś zaawansowaną manipulacje DOM-em (np. zbierz wszystkie elementy o klasie "aktywny" następnie pobierz ich pierwszy child po czym wypisz to w modalu).

A więc do czego zmierzam? Czy w reacie da się wszelkie manipulacje obsłużyć tak jak w jq/js ? Czy jesli state/refs nie wystarczają to aż takim dużym błędem bedzie uzycie np. jq/js ? Plus spotkałem sie ze stwierdzeniem że w reac.js trzeba unikać "manipulacji DOM-em". Tylko jak jej niby uniknąć? Przecież strona musi mieć jakieś zaawansowane mechanizmy reagujące na posunięcia użytkownika. Chyba pod względem technicznym czegoś tu nie rozumiem.

0

Na pewno odpada pomysł z jQuery, bo jest już przestarzałe i nie trzeba z tego korzystać. Wszystkie przeglądarki wspierają już querySelector, oraz querySelectorAll i manipulowanie DOMem w zwykłym JavaScripcie nie stanowi takiego problemu jak kiedyś.

TheSinOfGreed napisał(a):

to już kompletnie gubie się jeśli muszę zrobić jakaś zaawansowaną manipulacje DOM-em (np. zbierz wszystkie elementy o klasie "aktywny" następnie pobierz ich pierwszy child po czym wypisz to w modalu).

Jest kilka sposobów żeby to zrobić i musisz wybrać odpowiedni do swojej apki, bo możesz

  1. Zapisać fragment DOM do zwyklego state'u
  2. Skorzystać z context jeśli jest dużo komponentów i nie można tego przekazać w prosty sposób przez props
  3. Połączyć ref z jakimś querySelector i wyszukać za pomocą zwykłego selektora

I jeśli Twój przykład miałby taką strukturę

<div className="wrapper" ref={ref}>
   <div className="active">
      <span>hello</span>
      <span>world</span>
   </div>
    ... 
    ... Tutaj jakieś inne divy
    ...
    <div className="active">
       <span>hello</span>
       <span>world</span>
    </div>
</div>

to żeby pobrać teraz pierwsze childy z elementów active to można połączyć ref z querySelectorAll

ref.current.querySelectorAll(":scope .active > :first-child")
0

Pytanie, czy naprawdę masz potrzebę manipulacji DOMem, czy po prostu nie rozumiesz założeń Reacta.

W React manipuluje się DOMem głównie wtedy, kiedy osadzasz zewnętrzny widżet, która nie korzysta z Reacta. Ew. jeśli z jakichś powodów (bardzo specyficznych!) musisz mieć dostęp do DOMu, żeby porobić specyficzne dla aplikacji haki.

Ogólnie jednak w React manipulację DOMem należy traktować jak tylną furtkę, a nie jak coś normalnego. Zakładając normalną pracę i standardowe problemy, to:

już kompletnie gubie się jeśli muszę zrobić jakaś zaawansowaną manipulacje DOM-em

myślę, że nie do końca myślisz jeszcze w sposób reactowy. Co to znaczy musisz zrobić manipulację DOMem? Prawdopodobnie tylko wydaje ci się, że musisz (poza sytuacjami powyżej).

(np. zbierz wszystkie elementy o klasie "aktywny" następnie pobierz ich pierwszy child po czym wypisz to w modalu).

Myślę, że problemem jest to, że myślisz w kategoriach elementów DOM jako o czymś stałym (same założenia Reacta są takie, żeby o tym nie myśleć, tylko myśleć w kategorii komponentów, które mają jakieś dane na wejściu (propsy, stan, kontekst) i zwracają na tej podstawie informacje, jak powinien wyglądać dany komponent, jakie ma mieć elementy w środku (An element is like a single frame in a movie: it represents the UI at a certain point in time. oraz In our experience, thinking about how the UI should look at any given moment, rather than how to change it over time, eliminates a whole class of bugs. https://reactjs.org/docs/rendering-elements.html)

Czyli - próbujesz robić tak jak w jQuery i zakładasz, że elementy DOM są zamontowane na stałe i masz tam wielką piaskownicę i że możesz trzymać sobie stan aplikacji w elementach DOM. A React (podobnie jak cała reszta podobnych bibliotek) mówi "stop. Oddzielmy stan aplikacji od jej wyglądu".

próbujesz zrobić coś takiego (w pseudokodzie)

html = <ul>
  <li>Warszawa</li>
  <li>Kraków</li>
</ul>
.......
$("ul li").first().html("Wrocław")

a powinieneś zrobić tak (również w pseudokodzie)

cities = ["Warszawa", "Kraków"]
html = <ul>
   map each city in cities: <li>{{ city }}</li>
</ul>
........
cities[0] = "Wrocław"

Czyli - trzymać dane/stan aplikacji osobno (czy to w stanie React, czy używając Redux, Mobx czy innej biblioteki, to już rybka), a komponenty traktować jako coś, co ma jakieś wejście(propsy, stan itp.) i na podstawie tego wypluwa to, jak komponent ma wyglądać na wyjściu (czyli paradygmat deklaratywny zamiast imperatywnego)

Jeśli chcesz zmienić coś w aplikacji, to nie tykasz DOMu, tylko idziesz wyżej, do źródła twoich danych (np. stan w React, store w Redux itp. w zależności od tego, jak trzymasz dane) i wykonujesz działanie, które zmieni to źródło danych. Jak zmienisz źródło danych, to się automatycznie zmienią komponenty (pod warunkiem, że będą wiedzieć o tych zmianach, ale to już jest kwestia techniczna zależna od tego, w jaki sposób trzymasz dane i jak się do nich subskrybujesz). Np. prosty komponent funkcyjny:

function Foo() {
   const [counter, setCounter] = useState(0);
   return <button onClick={() => setCounter(x => x + 1)}>{ counter }</button>
}

zamiast manipulacji DOMem masz setCounter, który sprawia, że komponent się przerenderuje, a zmienna counter będzie już większa o 1.

Może być też tak, że twój problem wiąże się ze skalą. Łatwo jest zrobić to na jednym komponencie, ale jak zrobić to na wielu zagnieżdżonych? Bo myślę, że twój problem może wypływać po części z chęci manipulowania wieloma komponentami na raz:

No ale znowu, społeczność Reacta też ma na to rady np.

(np. zbierz wszystkie elementy o klasie "aktywny" następnie pobierz ich pierwszy child po czym wypisz to w modalu).

Raczej powinieneś mieć gdzieś tablicę (trzymaną np. w stanie reactowym) taką:

[
  {id: 1, name: "Warszawa", active: true},
  {id: 2, name: "Kraków", active: false},
  {id: 3, name: "Wrocław", active: false},
]

i operować na takiej liście

  • możesz wyrenderować całą tablicę (mapując każdy element tablicy do jakiegoś elementu w JSX), tutaj id się przydaje do przekazania właściwości key czy ogólnie identyfikowania elementów.
  • jeśli chcesz pobrać pierwszy element robisz to pobierając pierwszy element tablicy i to przekazać do komponentu renderującego modal
  • jeśli chcesz zmienić active to zamiast zmieniać coś w DOM, to zmieniasz element w tej tablicy (czy raczej tworzysz nową tablicę z elementem, który jest zmienioną kopią, żeby było wszystko immutable. Nie powinno się zmieniać stanu Reacta "na pałę")
0

Piszę sporo w React, stworzyłem kilka produkcyjnych apek, które używają tysiące ludzi. Nigdy od kiedy programuję w React nie miałem potrzeby żeby manipulować DOM lub używać funkcji querySelector i innych do czytania drzewa DOM.

Jeżeli masz taką potrzebę, to po prostu musisz się jeszcze pouczyć React, ponieważ najwyraźniej nie rozumiesz jak to działa.

Celem React jest stworzenie abstrakcji na drzewie DOM, tak aby na podstawie struktur danych, które masz w state czy props wygenerować drzewo DOM, tak abyś nie musiał w ogóle się tym zajmować. Zatem jeżeli przykładowo użytkownik wypełnia formularz, to pod spodem w React wszystko zapisujesz w state. Gdy teraz potrzebujesz przykładowo te dane wysłać do API, to po prostu czytasz je ze state. Podobnie w drugą stronę, jeżeli musisz przeczytać jakieś dane z API, to zapisujesz je w state, a React sam generuje drzewo DOM.

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