Pochodzę ze świata kątowego, w którym mogłem wyodrębnić logikę do usługi / fabryki i skonsumować ją w moich kontrolerach.
Próbuję zrozumieć, jak mogę osiągnąć to samo w aplikacji React.
Powiedzmy, że mam komponent, który weryfikuje wprowadzone hasło użytkownika (jest to siła). Jego logika jest dość złożona, dlatego nie chcę zapisywać jej w komponencie, który sam jest.
Gdzie mam napisać tę logikę? W sklepie, jeśli używam topnika? Czy jest lepsza opcja?
reactjs
reactjs-flux
Dennis Nerush
źródło
źródło
Odpowiedzi:
Pierwsza odpowiedź nie odzwierciedla obecnego paradygmatu kontenera i prezentera .
Jeśli musisz coś zrobić, na przykład zweryfikować hasło, prawdopodobnie masz funkcję, która to robi. Przekazałbyś tę funkcję do widoku wielokrotnego użytku jako rekwizyt.
Pojemniki
Tak więc poprawnym sposobem na zrobienie tego jest napisanie ValidatorContainer, który będzie miał tę funkcję jako właściwość i zawinięcie w nią formularza, przekazując odpowiednie rekwizyty dziecku. Jeśli chodzi o widok, kontener walidatora otacza widok, a widok zużywa logikę kontenerów.
Walidację można przeprowadzić we właściwościach kontenera, ale jeśli używasz walidatora innej firmy lub dowolnej prostej usługi walidacji, możesz użyć usługi jako właściwości komponentu kontenera i użyć jej w metodach kontenera. Zrobiłem to dla spokojnych komponentów i działa to bardzo dobrze.
Dostawcy
Jeśli wymagana jest nieco większa konfiguracja, możesz użyć modelu dostawcy / konsumenta. Dostawca to komponent wysokiego poziomu, który znajduje się w pobliżu i poniżej najwyższego obiektu aplikacji (tego, który montujesz) i dostarcza część samego siebie lub właściwość skonfigurowaną w górnej warstwie do kontekstowego interfejsu API. Następnie ustawiam elementy kontenera, aby zużywały kontekst.
Relacje kontekstu rodzic / dziecko nie muszą być blisko siebie, po prostu dziecko musi w jakiś sposób zejść. W ten sposób Redux przechowuje i React Router. Użyłem go, aby zapewnić korzeń kontekstu odpoczynku dla moich kontenerów odpoczynku (jeśli nie podam własnego).
(uwaga: kontekstowy interfejs API jest oznaczony jako eksperymentalny w dokumentacji, ale nie sądzę, aby był już dłużej, biorąc pod uwagę, co go używa).
Oprogramowanie pośredniczące
Kolejnym sposobem, którego nie próbowałem, ale widziałem, że jest używany, jest użycie oprogramowania pośredniczącego w połączeniu z Redux. Obiekt usługi definiujesz poza aplikacją lub przynajmniej wyżej niż sklep redux. Podczas tworzenia sklepu wstrzykujesz usługę do oprogramowania pośredniego, a oprogramowanie pośredniczące obsługuje wszelkie akcje, które mają wpływ na usługę.
W ten sposób mogłem wstrzyknąć obiekt restful.js do oprogramowania pośredniego i zastąpić metody kontenera niezależnymi akcjami. Nadal potrzebowałbym komponentu kontenera, aby dostarczyć akcje do warstwy widoku formularza, ale connect () i mapDispatchToProps mają mnie tam omówione.
Nowa wersja react-router-redux wykorzystuje tę metodę na przykład do wpływania na stan historii.
źródło
Problem staje się niezwykle prosty, gdy zdasz sobie sprawę, że usługa Angular to tylko obiekt, który dostarcza zestaw metod niezależnych od kontekstu. To tylko mechanizm Angular DI sprawia, że wygląda bardziej skomplikowanie. DI jest przydatny, ponieważ zajmuje się tworzeniem i utrzymywaniem instancji, ale tak naprawdę go nie potrzebujesz.
Rozważ popularną bibliotekę AJAX o nazwie axios (o której prawdopodobnie słyszałeś):
Czy nie zachowuje się jak usługa? Zapewnia zestaw metod odpowiedzialnych za określoną logikę i jest niezależny od głównego kodu.
Twój przykład dotyczył stworzenia izolowanego zestawu metod sprawdzania poprawności danych wejściowych (np. Sprawdzania siły hasła). Niektórzy sugerowali umieszczenie tych metod w komponentach, co dla mnie jest ewidentnie anty-wzorcem. Co jeśli walidacja obejmuje wykonywanie i przetwarzanie wywołań XHR backendu lub wykonywanie złożonych obliczeń? Czy mógłbyś połączyć tę logikę z funkcjami obsługi kliknięć myszą i innymi elementami interfejsu użytkownika? Nonsens. To samo z podejściem kontenerowym / HOC. Pakowanie komponentu tylko po to, aby dodać metodę, która sprawdzi, czy wartość zawiera cyfrę? Daj spokój.
Po prostu utworzyłbym nowy plik o nazwie „ValidationService.js” i zorganizowałbym go w następujący sposób:
Następnie w swoim komponencie:
Korzystaj z tej usługi z dowolnego miejsca. Jeśli zasady sprawdzania poprawności ulegną zmianie, należy skupić się tylko na pliku ValidationService.js.
Możesz potrzebować bardziej skomplikowanej usługi, która zależy od innych usług. W takim przypadku plik usługi może zwrócić konstruktor klasy zamiast obiektu statycznego, dzięki czemu można samodzielnie utworzyć instancję obiektu w komponencie. Można również rozważyć zaimplementowanie prostego singletona, aby upewnić się, że w całej aplikacji jest zawsze używane tylko jedno wystąpienie obiektu usługi.
źródło
Potrzebowałem pewnej logiki formatowania, która byłaby współdzielona przez wiele komponentów, a jako programista Angular również naturalnie skłaniałem się ku usłudze.
Podzieliłem się logiką, umieszczając ją w osobnym pliku
a następnie zaimportować go jako moduł
źródło
Pamiętaj, że celem Reacta jest lepsze połączenie rzeczy, które logicznie powinny być połączone. Jeśli projektujesz skomplikowaną metodę „walidacji hasła”, gdzie powinna być połączona?
Będziesz musiał go używać za każdym razem, gdy użytkownik będzie musiał wprowadzić nowe hasło. Może to być ekran rejestracji, ekran „zapomniałem hasła”, ekran administratora „resetowanie hasła innego użytkownika” itp.
Ale w każdym z tych przypadków zawsze będzie on powiązany z jakimś polem wprowadzania tekstu. Więc to jest miejsce, w którym powinno być połączone.
Stwórz bardzo mały komponent React, który składa się wyłącznie z pola wejściowego i powiązanej logiki walidacji. Wprowadź ten składnik we wszystkich formularzach, które mogą wymagać wprowadzenia hasła.
Zasadniczo jest to ten sam wynik, co posiadanie usługi / fabryki logiki, ale łączysz ją bezpośrednio z wejściem. Więc teraz nigdy nie musisz mówić tej funkcji, gdzie ma szukać swoich danych wejściowych walidacji, ponieważ jest ona trwale związana.
źródło
Pochodzę też z obszaru Angular.js, a usługi i fabryki w React.js są prostsze.
Możesz używać prostych funkcji lub klas, stylu wywołania zwrotnego i zdarzenia Mobx jak ja :)
Oto prosty przykład:
źródło
Ta sama sytuacja: po wykonaniu wielu projektów Angular i przejściu do React, brak prostego sposobu świadczenia usług za pośrednictwem DI wydaje się brakującym elementem (poza szczegółami usługi).
Korzystając z dekoratorów Context i ES7, możemy zbliżyć się:
https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/
Wygląda na to, że ci goście poszli o krok dalej / w innym kierunku:
http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs
Nadal ma się ochotę pracować pod włosem. Wrócę do tej odpowiedzi za 6 miesięcy po podjęciu dużego projektu React.
EDYCJA: Wróć 6 miesięcy później z większym doświadczeniem w React. Rozważ naturę logiki:
Niektórzy sięgają również po HOC-y do ponownego wykorzystania, ale dla mnie powyższe obejmuje prawie wszystkie przypadki użycia. Rozważ również skalowanie zarządzania stanem za pomocą kaczek, aby oddzielić obawy i skoncentrować się na interfejsie użytkownika.
źródło
Jestem również z Angulara i wypróbowuję Reacta, jak na razie wydaje się, że jednym zalecanym (?) Sposobem jest używanie komponentów wysokiego zamówienia :
Powiedzmy, że masz
input
itextarea
i chcesz zastosować tę samą logikę walidacji:Następnie napisz HOC, który sprawdza poprawność i stylizuje opakowany komponent:
Teraz te HOC mają to samo zachowanie podczas walidacji:
Stworzyłem proste demo .
Edycja : Kolejne demo używa właściwości do przekazywania tablicy funkcji, dzięki czemu możesz udostępniać logikę złożoną z wielu funkcji walidacyjnych w różnych
HOC
s, takich jak:Edit2 : React 16.8+ zapewnia nową funkcję, Hook , kolejny fajny sposób na dzielenie się logiką.
https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js
źródło
HOC
, zobacz moją edycję dla innego demo.Usługa nie ogranicza się do Angulara , nawet w Angular2 + ,
Usługa to po prostu zbiór funkcji pomocniczych ...
Istnieje wiele sposobów ich tworzenia i ponownego wykorzystywania w całej aplikacji ...
1) Mogą to być wszystkie oddzielne funkcje, które są eksportowane z pliku js, podobnie jak poniżej:
2) Możemy również użyć metody fabrycznej, takiej jak zbiór funkcji ... w ES6 może to być klasa, a nie konstruktor funkcji:
W takim przypadku musisz utworzyć instancję z nowym kluczem ...
Również w tym przypadku każda instancja ma swoje własne życie, więc bądź ostrożny, jeśli chcesz ją udostępnić, w takim przypadku powinieneś wyeksportować tylko tę instancję, którą chcesz ...
3) Jeśli twoja funkcja i narzędzia nie będą udostępniane, możesz nawet umieścić je w komponencie React, w tym przypadku, tak samo jak funkcje w komponencie React ...
4) Innym sposobem, w jaki możesz sobie z tym poradzić, może być użycie Redux , jest to tymczasowy magazyn dla ciebie, więc jeśli masz go w swojej aplikacji React , może ci pomóc z wieloma funkcjami getter setter których używasz ... To jest jak duży sklep które śledzą twoje stany i mogą udostępniać je w twoich komponentach, dzięki czemu mogą pozbyć się wielu problemów związanych z elementami ustawiającymi getter, których używamy w usługach ...
Zawsze dobrze jest zrobić kod DRY i nie powtarzać tego, co jest potrzebne, aby kod był wielokrotnego użytku i czytelny, ale nie próbuj podążać za ścieżkami Angulara w aplikacji React , jak wspomniano w punkcie 4, użycie Redux może zmniejszyć potrzebę usług i ograniczasz używanie ich do niektórych funkcji pomocniczych wielokrotnego użytku, takich jak pozycja 1 ...
źródło
Jestem w takim samym bucie jak ty. W przypadku, o którym wspomniałeś, zaimplementowałbym komponent UI walidacji danych wejściowych jako komponent React.
Zgadzam się, że implementacja samej logiki walidacji nie powinna (nie może) być łączona. Dlatego umieściłbym go w osobnym module JS.
Oznacza to, że dla logiki, która nie powinna być łączona, użyj modułu / klasy JS w oddzielnym pliku i użyj funkcji require / import w celu odłączenia komponentu od „usługi”.
Pozwala to na niezależne wstrzykiwanie i testowanie jednostkowe tych dwóch niezależnie.
źródło
lub możesz wstrzyknąć dziedziczenie klas „http” do komponentu React
za pośrednictwem obiektu props.
aktualizacja :
Po prostu edytuj React Component ReactApp w ten sposób:
źródło
Cóż, najczęściej używanym wzorcem logiki wielokrotnego użytku, z jakim się spotkałem, jest napisanie hooka lub utworzenie pliku utils. To zależy od tego, co chcesz osiągnąć.
Na przykład, jeśli chcesz sprawdzić poprawność danych formularza, utworzyłbym niestandardowy punkt zaczepienia o nazwie useForm.js i udostępniłby mu dane formularza, a w zamian zwróciłbym mi obiekt zawierający dwie rzeczy:
Z pewnością możesz zwrócić z niego więcej rzeczy w miarę postępów.
Innym przykładem może być wyodrębnienie niektórych informacji z adresu URL, a następnie utworzę dla niego plik utils zawierający funkcję i zaimportuj go w razie potrzeby:
źródło