2016-05-11 27 views
5

Należy rozważyć następujący kod clojurescript, w którym używane są frameworki widmowe, odczynnikowe i ramek ponownie ramek, jako komponent widoku używany jest zewnętrzny komponent siatki React.js.Jak przełączyć kolekcję subskrypcji w ramce ponownie i wyświetlić dane jako element listy?

W db.cls:

(def default-db 
    {:cats [{:id 0 :data {:text "ROOT" :test 17} :prev nil :par nil} 
      {:id 1 :data {:text "Objects" :test 27} :prev nil :par 0} 
      {:id 2 :data {:text "Version" :test 37} :prev nil :par 1} 
      {:id 3 :data {:text "X1" :test 47} :prev nil :par 2}]}) 

W subs.cls

(register-sub 
    :cats 
    (fn [db] 
    (reaction 
     (select [ALL :data] (t/tree-visitor (get @db :cats)))))) 

wynik od wybierz:

[{:text "ROOT", :test 17} 
{:text "Objects", :test 27} 
{:text "Version", :test 37} 
{:text "X1", :test 47}] 

W views.cls

(defn categorymanager [] 
     (let [cats (re-frame/subscribe [:cats])] 
     [:> Reactable.Table 
      {:data (clj->js @cats)}])) 

Powyższy kod działa zgodnie z oczekiwaniami.

Zamiast wyświetlać dane za pomocą komponentu react.js, chcę przejrzeć każdą z map w: kocie wektor i wyświetlić: elementy tekstowe w html ul/li.

zacząłem następująco:

(defn categorymanager2 [] 
     (let [cats (re-frame/subscribe [:cats])] 
     [:div 
      [:ul 
      (for [category @cats] 
;;--- How to continue here ?? --- 
     ) 
     )) 

oczekiwany wynik:

ROOT 
Objects 
Version 
X1 

Jak mogę pętla przez subskrybowanych kolekcji w ramie i ponownego wyświetlania danych jako lista-sprzęcie? (= pytanie o tytuł).

Odpowiedz

20

Pierwszy, być jasne, dlaczego używasz key ...

Podanie key dla każdej pozycji na liście jest przydatna, gdy ta lista jest dość dynamiczny - gdy nowe elementy listy są regularnie dodawane i usuwane, zwłaszcza jeśli lista jest długa, a elementy są dodawane/usuwane w górnej części listy.

keys może przynieść duże zyski wydajności, ponieważ umożliwiają one bardziej wydajne ponowne rysowanie tych zmiennych list. A dokładniej, pozwala Reactowi na uniknięcie przerysowywania przedmiotów, które mają ten sam klucz co poprzednio, a które się nie zmieniły, a które po prostu przesunęły się w górę lub w dół.

drugie, być jasne, co należy zrobić, jeśli lista jest dość statyczne (nie zmienia się cały czas), czy nie ma unikalną wartość związana z każdej pozycji ...

Don w ogóle używają :key. Zamiast tego użyj into w ten sposób:

(defn categorymanager [] 
    (let [cats (re-frame/subscribe [:cats])] 
    (fn [] 
     [:div 
     (into [:ul] (map #(vector :li (:text %)) @cats))]))) 

Zawiadomienie o tym, co się tutaj wydarzyło.Lista dostarczona przez map jest złożona into wektor into. Na końcu nie widać żadnej listy. Po prostu zagnieżdżone wektory.

Ostrzeżenia o brakujących kluczach pojawiają się tylko w przypadku osadzenia elementu list w czkawkę. Powyżej nie ma wbudowanego list, tylko vectors.

trzecie, jeśli lista jest naprawdę dynamiczny ...

Dodaj unikalny key każdej pozycji (unikatowy rodzeństwa jest standardem). W podanym przykładzie, sama :text jest wystarczająco dobry key (zakładam, że jest niepowtarzalny):

(defn categorymanager [] 
    (let [cats (re-frame/subscribe [:cats])] 
    (fn [] 
     [:div 
     [:ul (map #(vector :li {:key (:text %)} (:text %)) @cats)]]))) 

To map spowoduje list który jest 1 parametr do [:ul]. Kiedy Reagent/React widzi, że list będzie chciał zobaczyć keys na każdym elemencie (pamiętasz, że listy różnią się od wektorów w czapce odczynnika) i wydrukuje ostrzeżenia na konsolę, były one niedostępne keys.

Dlatego musimy dodać key do każdej pozycji z list. W powyższym kodzie nie dodajemy :key za pośrednictwem metadanych (chociaż można to zrobić w ten sposób, jeśli chcesz), a zamiast tego dostarczamy key poprzez 1. parametr (z [:li]), który zwykle przenosi również dane stylu.

Wreszcie - część 1 NIE używaj map-indexed jak sugeruje się w innej odpowiedzi.

key powinna być unikalną wartością związaną z każdym przedmiotem. Dołączenie jakiejś liczby całkowitej arb nie przynosi pożytku - cóż, pozbędzie się ostrzeżeń w konsoli, ale powinieneś użyć powyższej techniki, jeśli tego chcesz.

Wreszcie - część 2 nie ma różnicy między map i for w tym kontekście.

Oba skutkują list. Jeśli ten list ma klucze, to nie ma ostrzeżenia. Ale jeśli brakuje kluczy, to wiele ostrzeżeń. Ale sposób, w jaki utworzono listę, nie wchodzi w jej skład.

Ta wersja for jest prawie taka sama jak wersja map. Niektórzy mogą go wolą:

(defn categorymanager [] 
    (let [cats (re-frame/subscribe [:cats])] 
    (fn [] 
     [:div 
     [:ul (for [i @cats] [:li {:key (:text i)} (:text i)])]]))) 

który może być także napisane przy użyciu metadanych takiego:

(defn categorymanager [] 
    (let [cats (re-frame/subscribe [:cats])] 
    (fn [] 
     [:div 
     [:ul (for [i @cats] ^{:key (:text i)}[:li (:text i)])]]))) 

Finally - część 3

mapv jest problem, ponieważ od tej kwestii: https://github.com/Day8/re-frame/wiki/Using-%5Bsquare-brackets%5D-instead-of-%28parentheses%29#appendix-2

+1

Perły od twórcy re-frame! Dziękuję Ci!!! –

+0

Podczas reddit twoja odpowiedź została opisana jako epicka. :-) –

1

Oto przykład ul/li:

(defn phone-component 
    [phone] 
    [:li 
    [:span (:name @phone)] 
    [:p (:snippet @phone)]]) 

(defn phones-component 
    [] 
    (let [phones (re-frame/subscribe [:phones])] ; subscribe to the phones value in our db 
    (fn [] 
     [:ul (for [phone in @phones] ^{:key phone} [phone-component phone] @phones)]))) 

złapałem tego kodu z this reframe tutorial.

Również przy korzystaniu z odczynnika lepiej jest map niż for. Jest na to techniczny powód, po prostu nie wiem, co to jest.

2

Edytuj: Aby uzyskać bardziej spójne i technicznie poprawne wyjaśnienie klawiszy i map, patrz odpowiedź: Mike Thompson!


Oto jak byłoby to napisać:

(defn categorymanager2 [] 
    (let [cats (re-frame/subscribe [:cats])] 
    (fn [] 
     [:div 
     [:ul 
     (map-indexed (fn [n cat] ;;; !!! See https://stackoverflow.com/a/37186230/500207 !!! 
         ^{:key n} 
         [:li (:text cat)]) 
        @cats)]]))) 
(defn main-panel [] 
    [:div 
    [categorymanager2]]) 

Kilka punktów:

  1. Zobacz re-frame readme's Subscribe section, zbliża się do końca, który mówi:

    subskrypcje można używać tylko w komponentach Form-2 i subskrypcji mu st być w zewnętrznej funkcji ustawień, a nie w wewnętrznej funkcji renderowania. Więc dodaje się źle (w porównaniu do prawidłowej wersji powyżej) ...

    • Dlatego komponent był „zły”, ponieważ nie owijać renderujący wewnątrz wewnętrznej funkcji.Readme ma wszystkie szczegóły, ale w skrócie, nie zawijanie renderera komponentu, który zależy od subskrypcji wewnątrz funkcji wewnętrznej, jest złe, ponieważ powoduje to ponowne wygenerowanie komponentu po zmianie db - nie to, czego potrzebujesz! Chcesz, aby komponent tylko ponownie się wydał po zmianie subskrypcji.
  2. Edytuj: na poważnie, zobacz Mike Thompson's answer. Z jakiegokolwiek powodu wolę używać map do utworzenia seq znaczników Hiccup. Można również użyć pętli for, ale krytycznym punktem jest to, że każdy wektor obcęgowy [:li] potrzebuje wpisu :key w swoich metadanych, które dodaję tutaj, używając indeksu bieżącej kategorii w wektorze @cats. Jeśli nie masz :key, React złoży skargę w Konsoli Dysku. Zauważ, że ten klucz powinien jakoś jednoznacznie związać ten element @cats z tym znacznikiem: jeśli subskrypcja zmienia się i jest tasowana, wynik może nie być tym, czego oczekujesz, ponieważ użyłem właśnie tego bardzo prostego klucza. Jeśli możesz zagwarantować, że nazwy kategorii będą unikatowe, możesz po prostu użyć wartości :test lub wartości :test lub czegoś innego. Chodzi o to, że klucz musi być unikalny i musi jednoznacznie identyfikować ten element.
    • (Uwaga: nie należy próbować używać mapv dokonać wektor z czkawką tagów-re-ramie nienawidzi, które muszą być seq jak co map produkuje..)
  3. ja również przykładem main-panel podkreślić, że
    • elementy dominujące nie trzeba subskrypcje, że ich dzieci potrzebują komponent oraz że
    • należy wywoływać komponent categorymanager2 z nawiasami kwadratowymi zamiast z funkcją parens (patrz Using [] instead of()).
+0

Ta odpowiedź jest b Bardzo pomocne. Dziękuję Ci. –