Back to Question Center
0

Zbuduj aplikację CRUD za pomocą React, Redux i FeathersJS            Zbuduj aplikację CRUD przy użyciu React, Redux i FeathersJSRelated Semalt: APIsNode.jsAngularJSjQueryAjaxMore ... Sponsorzy

1 answers:
Utwórz aplikację CRUD za pomocą React, Redux i FeathersJS

Aby uzyskać wysokiej jakości, dogłębne wprowadzenie do React, nie można przejść obok kanadyjskiego producenta pełnych kominków Wesa Bosa. Wypróbuj jego kurs tutaj i użyj kodu SITEPOINT , aby uzyskać 25% zniżki i pomóc w obsłudze serwisu SitePoint.

Semalt, współczesny projekt wymaga podziału logiki na kod front-end i back-end - tema wordpress para site de hospedagem. Powodem tego ruchu jest promowanie ponownego użycia kodu. Na przykład możemy potrzebować zbudować natywną aplikację mobilną, która uzyskuje dostęp do interfejsu API zaplecza. Lub możemy rozwijać moduł, który będzie częścią dużej platformy modułowej.

Popularnym sposobem budowania interfejsu API po stronie serwera jest użycie biblioteki takiej jak Express lub Restify. Te biblioteki ułatwiają tworzenie RESTful tras. Problem z tymi bibliotekami polega na tym, że napiszemy sobie ton z powtarzającego się kodu . Będziemy również musieli napisać kod autoryzacji i inną logikę oprogramowania pośredniego.

Aby uniknąć tego dylematu, możemy wykorzystać strukturę taką jak Loopback lub Feathers, aby pomóc nam wygenerować API.

W czasie pisania, Semalt ma więcej gwiazd i pobrań GitHub niż Pióra. Semalt to świetna biblioteka do generowania punktów końcowych RESTful CRUD w krótkim czasie. Jednak ma niewielką krzywą uczenia się i dokumentacji nie jest łatwo pogodzić. Ma rygorystyczne wymagania ramowe. Na przykład wszystkie modele muszą dziedziczyć jedną z wbudowanych klas modeli. Jeśli potrzebujesz możliwości w czasie rzeczywistym w Semalt, przygotuj się na dodatkowe kodowanie, aby działało.

Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

Z kolei FeathersJS jest znacznie łatwiejszy w obsłudze i ma wbudowane wsparcie w czasie rzeczywistym. Całkiem niedawno wydano wersję Auk (ponieważ Feathers jest tak modułowa, używają nazw ptaków dla nazw wersji), która wprowadziła ogromną liczbę zmian i ulepszeń w wielu obszarach. Według postu, który publikowali na swoim blogu, są teraz 4. najpopularniejszym frameworkiem sieci czasu rzeczywistego . Ma doskonałą dokumentację i objął praktycznie każdy obszar, o którym możemy myśleć przy tworzeniu API w czasie rzeczywistym.

Tym, co sprawia, że ​​Pióra są niesamowite, jest jego prostota. Całe środowisko jest modułowe i musimy tylko zainstalować potrzebne funkcje. Samo pióro jest cienkim opakowaniem zbudowanym na Expressie, w którym dodano nowe funkcje - usługi i haki. Pióra umożliwiają również bezproblemowe wysyłanie i odbieranie danych przez WebSockets.

Wymagania wstępne

Semalt, który zaczynasz od samouczka, musisz mieć solidne podstawy w następujących tematach:

  • Jak pisać kod JavaScript ES6
  • Jak tworzyć składniki reakcji
  • Niezmienność w JavaScript
  • Jak zarządzać stanem z Redux

Na komputerze musisz zainstalować najnowsze wersje:

  • NodeJS 6+
  • Mongodb 3. 4+
  • Menedżer paczki przędzy (opcjonalnie)
  • Przeglądarka Chrome

Jeśli nigdy wcześniej nie pisałeś API bazy danych w JavaScript, polecam najpierw zapoznać się z tym samouczkiem dotyczącym tworzenia API RESTful.

Zalecane kursy

Scaffold the App

Będziemy budować aplikację do zarządzania kontaktami CRUD przy użyciu React, Redux, Feathers i SemaltDB. Tutaj możesz obejrzeć ukończony projekt.

W tym samouczku pokażę, jak zbudować aplikację od podstaw. Semalt uruchom nasz projekt za pomocą narzędzia do tworzenia aplikacji.

     # rusztowanie nowego projektu reakcjicreate-react-app react-contact-managercd react-contact-manager# usuń niepotrzebne plikirm src / logo. svg src / App. css    

Użyj swojego ulubionego edytora kodu i usuń całą zawartość w indeksie. css. Sprawdź zakładkę konsoli, aby upewnić się, że nasz projekt działa bez żadnych ostrzeżeń i błędów. Jeśli wszystko działa płynnie, użyj Ctrl + C , aby zatrzymać serwer.

Zbuduj serwer API z piórami

Zacznijmy od wygenerowania API zaplecza dla naszego projektu CRUD przy użyciu narzędzia feathers-cli .

     # Zainstaluj narzędzie wiersza polecenia Pióranpm install -g feathers-cli# Utwórz katalog dla kodu zapleczawsparcie mkdirwsparcie cd# Wygeneruj wtórny serwer API pióraPiórka generują aplikację? Nazwa projektu | backend? Opis | serwer interfejsu kontaktów? W jakim folderze powinny mieszkać pliki źródłowe? | src? Który menedżer pakietów używasz (musi być zainstalowany globalnie)? | Przędza? Jakiego typu API tworzysz? | REST, Realtime za pośrednictwem Socket. io# Generuj RESTful trasy dla modelu kontaktupióra generują usługę? Jaka to usługa? | Mangusta? Jak nazywa się usługa? | kontakt? Na jakiej ścieżce powinna zostać zarejestrowana usługa? | /Łączność? Co to jest ciąg połączenia z bazą danych? | mongodb: // localhost: 27017 / backend# Zainstaluj typ pola e-mailprzędza dodaje wiadomość typu mongoose-email# Zainstaluj pakiet nodemonprzędza dodaj nodemon --dev    

Backend / pakiet Open . json i zaktualizuj skrypt startowy tak, aby używał nodemon, aby serwer API uruchamiał się automatycznie po każdej zmianie.

     // backend / package. json."skrypty": { "start": "nodemon src /",.},.    

Otwórzmy backend / config / default. json . Tutaj możemy skonfigurować parametry połączenia MongoDB i inne ustawienia. Zwiększyłem również domyślną wartość paginacji do 50, ponieważ w tym samouczku nie będziemy pisać logiki front-end, aby zajmować się paginacją.

     {"host": "localhost","port": 3030,"publiczny": ". / public /","paginate": {"default": 50,"maks.": 50},"mongodb": "mongodb: // localhost: 27017 / backend"}    

Open backend / src / models / contact. Model. js i zaktualizować kod w następujący sposób:

     // backend / src / models / contact. Model. jsrequire ("e-mail typu mongoose");moduł. exports = function (app) {const mongooseClient = app. get ("mongooseClient");const contact = new mongooseClient. Schemat({imię : {pierwszy: {typ: String,required: [true, "Imię jest wymagane"]},ostatni, ubiegły, zeszły: {typ: String,wymagany: false}},e-mail : {typ: mongooseClient. SchemaTypes. E-mail,required: [true, "Email is required"]},telefon: {typ: String,wymagane: [true, "Telefon jest wymagany"],sprawdź: {validator: function (v) {return / ^ \ + (?: [0-9]?) {6,14} [0-9] $ /. test (v);},wiadomość: "{VALUE} nie jest prawidłowym międzynarodowym numerem telefonu!"}},createdAt: {type: Date, 'default': Date. teraz },updatedAt: {type: Date, 'default': Date. teraz }});wróć mongooseClient. model ("kontakt", kontakt);};    

Oprócz generowania usługi kontaktowej, Semalt wygenerował dla nas także przypadek testowy. Najpierw musimy naprawić nazwę usługi:

     // backend / test / services / contact. test. jsconst assert = require ('assert');const app = require ('././ src / app');opisz ('\' kontakt \ 'usługa',    => {it ('registered the service',    => {const service = app. usługa ("kontakty"); // zmień kontakt z kontaktamizapewniać. ok (usługa "Zarejestrowana usługa");});});    

Otwórz nowy terminal i wewnątrz katalogu zaplecza, wykonaj test przędzy . Powinieneś pomyślnie przejść wszystkie testy. Idź i uruchom start przędzy , aby uruchomić serwer zaplecza. Po zakończeniu uruchamiania serwera powinien wydrukować wiersz: "Uruchomiono aplikację piór na localhost: 3030 ' . Powinieneś spodziewać się następującej odpowiedzi JSON:

     {"całkowita": 0, "limit": 50, "pomiń": 0, "dane": []}    

Teraz użyjmy Semalta, aby potwierdzić, że działają wszystkie spokojne trasy CRUD. Możesz uruchomić Semalt za pomocą tego przycisku:

Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

Jeśli jesteś nowym użytkownikiem Postman, zapoznaj się z tym samouczkiem. Po naciśnięciu przycisku WYŚLIJ otrzymasz dane jako odpowiedź wraz z trzema dodatkowymi polami - _id , createdAt i updatedAt .

Użyj następujących danych JSON, aby wysłać żądanie POST za pomocą Listonosza. Wklej to w treści i ustaw typ zawartości na application / json :

     {"imię": {"pierwszy": "Tony","last": "Stark"},"telefon": "+18138683770","email": "tony @ starkenterprises. com"}    

Zbuduj interfejs użytkownika

Zacznijmy od zainstalowania niezbędnych zależności front-end. Semalt korzysta z semantic-ui css / semantic-ui, aby nadać styl naszym stronom i reagować-router-dom na obsługę nawigacji po trasie.

Ważne: Upewnij się, że instalujesz na zewnątrz katalog backendu

     // Zainstaluj semantic-uiprzędza dodaj semantyczny-ui-css semantyczny-ui-reaguj// Zainstaluj router reagowaniaprzędza dodaj react-router-dom    

Należy uśrednić strukturę projektu, dodając następujące katalogi i pliki:

     | - reagować-kontakt-kierownik| - backend| - node_modules| - publiczny| - src| - App. js| - App. test. js| - indeks. css| - indeks. js| - komponenty| | - formularz kontaktowy. js # (nowy)| | - lista kontaktów. js # (nowy)| - strony| - strona formularza kontaktowego. js # (nowy)| - strona z listą kontaktów. js # (nowy)    

Semalt szybko zapełnia pliki JS pewnym kodem zastępczym.

Dla listy kontaktów składnika . js , napiszemy to w tej składni, ponieważ będzie to komponent czysto prezentacyjny.

     // src / components / contact-list. jsimport Reaguj z "reaguj";eksportuj domyślną funkcję ContactList    {powrót ( 

Brak kontaktów tutaj

)}

Do kontenerów najwyższego poziomu używam stron. Podajmy kod dla strony listy kontaktów. js

     // src / pages / contact-list-page. jsimportuj Reaguj, {Komponent} od "reaguj";zaimportuj listę kontaktów z '. / components / contact-list ";klasa ContactListPage rozszerza komponent {renderowanie   {powrót ( 

Lista kontaktów

)}}wyeksportuj domyślną ContactListPage;

W przypadku komponentu formularza kontaktowego musi on być inteligentny, ponieważ wymaga zarządzania własnym państwem, w szczególności pól. Na razie umieścimy ten kod zastępczy.

     // src / components / contact-form. jsimportuj Reaguj, {Komponent} od "reaguj";klasa ContactForm rozszerza komponent {renderowanie   {powrót ( 

Formularz w trakcie budowy

)}}wyeksportuj domyślny formularz kontaktowy;

Wypełnij formularz kontaktowy tym kodem:

     // src / pages / contact-form-page. jsimportuj Reaguj, {Komponent} od "reaguj";importuj ContactForm z '. / komponenty / formularz kontaktowy ";klasa ContactFormPage rozszerza komponent {renderowanie   {powrót ( 
)}}eksportuj domyślną ContactFormPage;

Stwórzmy teraz menu nawigacyjne i określmy trasy naszej aplikacji. App. js jest często określany jako "szablon układu" dla aplikacji pojedynczej strony.

     // src / App. jsimportuj Reaguj, {Komponent} od "reaguj";zaimportuj {NavLink, Route} z "react-router-dom";import {Container} z "semantic-ui-react";importuj ContactListPage z '. / pages / contact-form-page ";klasa App rozszerza komponent {renderowanie   {powrót (   
Lista kontaktów Dodaj kontakt
<Ścieżka trasy = "/ kontakty / nowe" komponent = {ContactFormPage} /> <Ścieżka trasy = "/ kontakty / edytuj /: _ id" komponent = {ContactFormPage} /> );}}eksportuj domyślną aplikację;

Na koniec zaktualizuj indeks . js plik z tym kodem, w którym importujemy semantic-ui CSS do stylizacji i BrowserRoutera za pomocą interfejsu API historii HTML5, który utrzymuje synchronizację naszej aplikacji z adresem URL.

     // src / index. jsimport Reaguj z "reaguj";importuj ReactDOM z "react-dom";importuj {BrowserRouter} z "react-router-dom";importuj aplikację z ". / App ";import "semantic-ui-css / semantic. min. css ";import '. /indeks. css ";ReactDOM. renderowanie(      ,dokument. getElementById ("root"));    

Wróć do terminala i wykonaj start przędzy . Powinieneś mieć podobny widok do zrzutu ekranu poniżej:

Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

Zarządzaj React State with Redux

Zatrzymaj serwer za pomocą ctrl + c i zainstaluj następujące pakiety za pomocą menedżera pakietów przędzy:

     przędza dodaj redux reag-redux redux-promise-middleware redux-thunk redux-devtools-rozszerzenie axios    

Uff! To cała masa pakietów do ustawienia Semalta. Zakładam, że już znasz Semalt, jeśli czytasz ten samouczek. Semalt-thunk pozwala na pisanie twórców akcji jako funkcji asynchronicznych, podczas gdy redux-promise-middleware redukuje dla nas niektóre kody dla standardowego Semal poprzez obsługę wysyłania oczekujących, wykonanych i odrzuconych działań w naszym imieniu.

Pióra zawierają lekki pakiet klienta, który ułatwia komunikację z interfejsem API, ale jest także bardzo łatwy w użyciu innych pakietów klientów. W tym samouczku użyjemy klienta HTTP Semalt.

Rozszerzenie redux-devtools to niesamowite narzędzie, które śledzi wysłane akcje i zmiany stanu. Semalt musi zainstalować swoje rozszerzenie chrome, aby działało.

Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

Następnie skonfiguruj naszą strukturę katalogu Semalt w następujący sposób:

     | - reagować-kontakt-kierownik| - backend| - node_modules| - publiczny| - src| - App. js| - App. test. js| - indeks. css| - indeks. js| - dane kontaktowe. js #new| - Sklep. js #new| - actions #new| - działania kontaktowe. js #new| - indeks. js #new| - komponenty| - strony| - reduktory # now| - reduktor kontaktowy. js #new| - indeks. js #new    

Zacznijmy od zapełnienia danych kontaktowych. js z niektórymi danymi testowymi:

     // src / dane kontaktowe. jseksportuj kontakty const = [{_id: "1",imię: {po pierwsze: "John",last: "Doe"},telefon: "555",email: "john @ gmail. com"},{_id: "2",imię: {po pierwsze: "Bruce",ostatnio: "Wayne"},telefon: "777",email: "bruce. wayne @ gmail. com"}];    

Określ działania kontaktowe. js z następującym kodem. Na razie pobieramy dane z danych kontaktowych. plik js .

     // src / actions / contact-actions. jsimportuj {kontakty} z '. / contacts-data ";funkcja eksportu fetchContacts    {return dispatch => {wysyłka({type: "FETCH_CONTACTS",ładunek: kontakty})}}    

W reduktorze kontaktowym . js , napiszmy nasz program do akcji "FETCH_CONTACT" .

     // src / reduktory / reduktor kontaktowy. jsconst defaultState = {Łączność: []}export default (state = defaultState, action = {}) => {switch (action. type) {Przypadek "FETCH_CONTACTS": {powrót { stan,kontakty: akcja. ładunek}}domyślna:stan powrotu;}}    

In reduktorów / indeksów. js , połączymy wszystkie reduktory tutaj, aby ułatwić eksport do naszego sklepu Redux.

     // src / reducers / index. jsimport {combineReducers} z 'redux';importuje ContactReducer z ". / reduktor kontaktowy ";Reduktory const = {contactStore: ContactReducer}const rootReducer = combineReducers (reducers);wyeksportuj domyślny rootReducer;    

W sklepie. js , zaimportujemy niezbędne zależności, aby zbudować nasz sklep Redux. Przygotujemy również redux-devtools-extension , aby umożliwić nam monitorowanie sklepu Redux przy użyciu rozszerzenia Chrome.

     // src / store. jsimportuj {applyMiddleware, createStore} z "redux";import thunk z "redux-thunk";obietnica importu z "redux-promise-middleware";importuj {composeWithDevTools} z 'redux-devtools-extension';import rootReducer z ". / reducers";const middleware = composeWithDevTools (applyMiddleware (obietnica   , thunk));wyeksportuj domyślny createStore (rootReducer, middleware);    

Indeks otwarty . js i zaktualizuj metodę renderowania, w której wstrzykiwamy sklep za pomocą klasy dostawcy Redux.

     // src / index. jsimport Reaguj z "reaguj";importuj ReactDOM z "react-dom";importuj {BrowserRouter} z "react-router-dom";importuj {Provider} z "react-redux";importuj aplikację z ". / App ";importuj sklep z ". / store"import "semantic-ui-css / semantic. min. css ";import '. /indeks. css ";ReactDOM. renderowanie(          ,dokument. getElementById ("root"));    

Zacznijmy początek przędzy , aby upewnić się, że wszystko działa do tej pory.

Następnie połączymy naszą składową listę kontaktów z właśnie utworzonym przez nas magazynem Redux. Otwórz listę-kontaktów-strony i zaktualizuj kod w następujący sposób:

     // src / pages / contact-list-pageimportuj Reaguj, {Komponent} od "reaguj";importuj {link} z "react-redux";zaimportuj listę kontaktów z '. / components / contact-list ";importuj {fetchContacts} z '. / actions / contact-actions ";klasa ContactListPage rozszerza komponent {componentDidMount    {to. rekwizyty. fetchContacts   ;}renderowanie   {powrót ( 

Lista kontaktów

)}}// Przygotuj tablicę kontaktów w rekwizytachfunction mapStateToProps (state) {powrót {kontakty: stan. contactStore. Łączność}}eksportuj domyślne połączenie (mapStateToProps, {fetchContacts}) (ContactListPage);

Przygotowaliśmy tablicę kontaktów i udostępniliśmy funkcję fetchContacts dla składnika ContactListPage poprzez to. rekwizyty zmienne. Możemy teraz przekazać tablicę kontaktów do elementu ContactList .

Póki co, zaktualizujmy kod tak, abyśmy mogli wyświetlić listę kontaktów.

     // src / components / contact-listimport Reaguj z "reaguj";eksportuj domyślną funkcję ContactList ({contacts}) {const list =    => {wrócić kontakty. mapa (kontakt => {powrót ( 
  • {contact. Nazwa. pierwszy kontakt. Nazwa. last}
  • )})}powrót (
      {list }
    )}

    Jeśli wrócisz do przeglądarki, powinieneś mieć coś takiego:

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

    Uczyńmy wygląd UI bardziej atrakcyjnym za pomocą komponentu semantic-ui Card . js i wklej ten kod:

         // src / components / contact-card. jsimport Reaguj z "reaguj";import {Card, Button, Icon} z "semantic-ui-react"eksportuj domyślną funkcję ContactCard ({contact, deleteContact}) {powrót (         {kontakt. Nazwa. pierwszy kontakt. Nazwa. ostatni, ubiegły, zeszły}     

    {kontakt. telefon}

    {contact. email}

    Edytuj Usuń
    )}ContactCard. propTypes = {kontakt: React. PropTypes. obiekt. jest wymagane}

    Aktualizacja listy kontaktów do korzystania z nowego komponentu ContactCard

         // src / components / contact-list. jsimport Reaguj z "reaguj";import {Card} z "semantic-ui-react";importuj wizytówkę z ". / karta kontaktowa ";eksportuj domyślną funkcję ContactList ({contacts}) {const cards =    => {wrócić kontakty. mapa (kontakt => {powrót (  )})}powrót (  {cards   }  )}    

    Strona listy powinna teraz wyglądać następująco:

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

    Walidacja po stronie serwera za pomocą Redux-Form

    Teraz, gdy wiemy, że sklep Redux jest poprawnie powiązany z komponentami React, możemy teraz wysłać do bazy prawdziwe żądanie pobrania i użyć danych do wypełnienia naszej listy kontaktów. Jest na to kilka sposobów, ale sposób w jaki Semalt jest zaskakująco prosty.

    Najpierw musimy skonfigurować klienta Semalt, który może łączyć się z serwerem wewnętrznym.

         // src / actions / index. jsimportuj aksje z "axios";export const client = axios. Stwórz({baseURL: "http: // localhost: 3030",nagłówki: {"Content-Type": "application / json"}})    

    Następnie zaktualizujemy działania kontaktowe. js kod do pobierania kontaktów z bazy danych za pomocą żądania GET za pomocą klienta Axios.

         // src / actions / contact-actions. jszaimportuj {klienta} z '. / ";const url = '/ contacts';funkcja eksportu fetchContacts    {return dispatch => {wysyłka({type: "FETCH_CONTACTS",ładunek: klient. get (url)})}}    

    Reduktor kontaktu . js , ponieważ akcja i ładunek są teraz wysyłane.

         // src / reduktory / reduktor kontaktowy. js.case "FETCH_CONTACTS_FULFILLED": {powrót { stan,kontakty: akcja. ładunek. dane. dane || akcja. ładunek. dane // w przypadku wyłączenia stronicowania}}.    

    Po zapisaniu odśwież przeglądarkę i upewnij się, że serwer zaplecza działa na localhost: 3030 . Strona listy kontaktów powinna teraz wyświetlać dane z bazy danych.

    Obsługa tworzenia i aktualizowania żądań za pomocą formularza Redux

    Następnie przyjrzyjmy się, jak dodawać nowe kontakty, a do tego potrzebujemy formularzy. Na początku budowanie formy wygląda dość łatwo. Ale kiedy zaczynamy myśleć o walidacji po stronie klienta i kontrolowaniu, kiedy błędy powinny być wyświetlane, staje się trudne. Ponadto serwer zaplecza wykonuje swoją własną walidację, którą musimy również wyświetlić w formularzu.

    Zamiast implementować wszystkie funkcje formularzy sami, skorzystamy z pomocy biblioteki o nazwie Redux-Form. Użyjemy również fajnego pakietu o nazwie Semalt, który pomoże nam wyróżnić pola z błędami walidacyjnymi.

    Najpierw szybko dodajmy tę klasę css do indeksu . css plik do stylu formularza błędów:

         / * src / index. css * /. błąd {kolor: # 9f3a38;}    

    Dodajmy reduktor redux-form do funkcji CombineReducers w reduktorach / indeksach. js

         // src / reducers / index. js.import {reduktor jako formReducer} z 'redux-form';Reduktory const = {contactStore: ContactReducer,formularz: formReducer}.    

    Następnie należy otworzyć formularz kontaktowy. js i buduj formularz UI z tym kodem:

         // src / components / contact-formimportuj Reaguj, {Komponent} od "reaguj";import {Form, Grid, Button} z "semantic-ui-react";importuj {Field, reduxForm} z 'redux-form';importuj nazwy klas z "classnames";klasa ContactForm rozszerza komponent {renderField = ({input, label, type, meta: {touch, error}}) => (   

    Dodaj nowy kontakt

    Poświęć czas na sprawdzenie kodu; dużo się tam dzieje. Zobacz przewodnik referencyjny, aby zrozumieć, w jaki sposób działa redux-form. Zapoznaj się również z dokumentacją semantic-ui-react i przeczytaj o jej elementach, aby zrozumieć, w jaki sposób są one wykorzystywane w tym kontekście.

    Następnie określimy działania niezbędne do dodania nowego kontaktu do bazy danych. Pierwsze działanie zapewni nowy obiekt kontaktu do formularza Redux. Podczas gdy druga akcja opublikuje dane kontaktu na serwerze API.

    Dołącz następujący kod do działań związanych z kontaktami. js

         // src / actions / contact-actions. js.funkcja eksportu newContact    {return dispatch => {wysyłka({wpisz: "NEW_CONTACT"})}}funkcja eksportu saveContact (contact) {return dispatch => {wysyłka zwrotna ({wpisz: "SAVE_CONTACT",ładunek: klient. post (adres URL, kontakt)})}}    

    W reduktorze styków musimy obsłużyć działania dla "NEW_CONTACT" , "SAVE_CONTACT_PENDING" , "SAVE_CONTACT_FULFILLED" oraz "SAVE_CONTACT_REJECTED" . Musimy zadeklarować następujące zmienne:

    • kontakt - zainicjalizuj pusty obiekt
    • ładowanie - aktualizacja ui z informacją o postępie
    • błędy - błędy sprawdzania poprawności serwera przechowywania na wypadek, gdyby coś poszło nie tak

    Dodaj ten kod w środku przełącznik przełączania reduktora :

         // src / reduktory / reduktor kontaktowy. js.const defaultState = {Łączność: [],Nazwa Kontaktu:{}},ładowanie: false,błędy: {}}.Przypadek "NEW_CONTACT": {powrót {. .. stan,ładowanie: prawda}}Przypadek "SAVE_CONTACT_FULFILLED": {powrót { stan,Łączność: [ stan. kontakty, działanie. ładunek. dane],błędy: {},ładowanie: false}}Przypadek "SAVE_CONTACT_REJECTED": {const data = action. ładunek. odpowiedź. dane;// konwertuj formatowanie błędów piór, aby dopasować formatowanie błędów po stronie klientaconst {"name. first": first, "name. last": last, phone, email} = data. błędy;const errors = {global: data. wiadomość, imię i nazwisko: {pierwszy, ostatni}, telefon, e-mail};powrót { stan,błędy: błędy,ładowanie: false}}.    

    Otwórz formularz kontaktowy. js i zaktualizować kod w następujący sposób:

         // src / pages / contact-form-pageimportuj Reaguj, {Komponent} od "reaguj";importuj {Redirect} z "Reaktor-routera";importuj {SubmissionError} z 'redux-form';importuj {link} z "react-redux";importuj {newContact, saveContact} from '. / actions / contact-actions ";importuj ContactForm z '. / komponenty / formularz kontaktowy ";klasa ContactFormPage rozszerza komponent {stan = {przekierowanie: false}componentDidMount    {to. rekwizyty. nowy kontakt  ;}submit = (contact) => {zwróć to. rekwizyty. saveContact (kontakt). then (response => this. setState ({przekierowanie: true})). catch (err => {throw new SubmissionError (błędy rekwizytów)})}renderowanie   {powrót ( 
    {to. stan. przekierować? : }
    )}}function mapStateToProps (state) {powrót {kontakt: stan. contactStore. kontakt,błędy: stan. contactStore. błędy}}eksportuj domyślne połączenie (mapStateToProps, {newContact, saveContact}) (ContactFormPage);

    Semalt teraz wróć do przeglądarki i spróbuj celowo zapisać niekompletny formularz

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

    Jak widać, walidacja po stronie serwera uniemożliwia nam zapisanie niekompletnego kontaktu. Używamy klasy SubmissionError do przekazania tego. rekwizyty. błędy do formularza, na wypadek gdybyś się zastanawiał.

    Teraz dokończ wypełnianie formularza całkowicie. Kliknięcie przycisku Semalt powinno zostać skierowane na stronę listy.

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

    Sprawdzanie poprawności po stronie klienta za pomocą formularza Redux

    Rzućmy okiem na to, jak można wprowadzić walidację po stronie klienta. Otwórz formularz kontaktowy i wklej ten kod poza klasę ContactForm. Zaktualizuj domyślny eksport tak, jak pokazano:

         // src / components / contact-form. js.const validate = (values) => {const errors = {nazwa: {}};jeśli (! wartości. nazwa ||! wartości. nazwa. pierwszy) {błędy. Nazwa. first = {wiadomość: "Musisz podać imię"}}if (! value. phone) {błędy. phone = {wiadomość: "Musisz podać numer telefonu"}} else if (! / ^ \ + (?: [0-9]?) {6,14} [0-9] $ /. test (wartości telefonu)) {błędy. phone = {wiadomość: "Numer telefonu musi być w formacie międzynarodowym"}}if (! wartości. email) {błędy. email = {wiadomość: "Musisz podać adres e-mail"}} else if (! / ^ [A-Z0-9. _% + -] + @ [A-Z0-9. -] + \. [AZ] {2,4} $ / i. test (wartości. )) {błędy. email = {wiadomość: "Nieprawidłowy adres e-mail"}}błędy powrotu;}.wyeksportuj domyślny reduxForm ({form: 'contact', validate}) (ContactForm);    

    Semalt zapisuje plik, wróć do przeglądarki i spróbuj dodać nieprawidłowe dane. Tym razem walidacja po stronie klienta blokuje przesyłanie danych do serwera.

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

    Teraz, idź dalej i wprowadź prawidłowe dane. Powinniśmy mieć co najmniej trzy nowe kontakty.

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

    Zaimplementuj aktualizacje kontaktów

    Teraz możemy dodawać nowe kontakty, zobaczmy, jak możemy zaktualizować istniejące kontakty. plik js , w którym musimy zdefiniować dwie akcje - jedną do pobrania pojedynczego kontaktu, a drugą do aktualizacji kontaktu.

         // src / actions / contact-actions. js.funkcja eksportu fetchContact (_id) {return dispatch => {wysyłka zwrotna ({type: "FETCH_CONTACT",ładunek: klient. get (`$ {url} / $ {_ id}`)})}}funkcja eksportu updateContact (contact) {return dispatch => {wysyłka zwrotna ({typ: "UPDATE_CONTACT",ładunek: klient. put (`$ {url} / $ {contact. _id}`, contact)})}}    

    Dodajmy następujące przypadki do reduktora kontaktu , aby zaktualizować stan, gdy kontakt jest pobierany z bazy danych i kiedy jest aktualizowany.

         // src / reduktory / reduktor kontaktowy. js.Przypadek "FETCH_CONTACT_PENDING": {powrót { stan,ładowanie: prawda,Nazwa Kontaktu:{}}}}Przypadek "FETCH_CONTACT_FULFILLED": {powrót { stan,kontakt: akcja. ładunek. dane,błędy: {},ładowanie: false}}Przypadek "UPDATE_CONTACT_PENDING": {powrót { stan,ładowanie: prawda}}Przypadek "UPDATE_CONTACT_FULFILLED": {const contact = action. ładunek. dane;powrót { stan,kontakty: stan. Łączność. map (item => item. _id === contact. _id? contact: item),błędy: {},ładowanie: false}}Przypadek "UPDATE_CONTACT_REJECTED": {const data = action. ładunek. odpowiedź. dane;const {"name. first": first, "name. last": last, phone, email} = data. błędy;const errors = {global: data. wiadomość, imię i nazwisko: {pierwszy, ostatni}, telefon, e-mail};powrót { stan,błędy: błędy,ładowanie: false}}.    

    Następnie przepuśćmy nowe akcje pobierania i zapisywania na stronę formularza kontaktowego . js . Zmienimy również logikę componentDidMount i submit , aby obsłużyć zarówno scenariusze tworzenia, jak i aktualizacji. Pamiętaj, aby zaktualizować każdą sekcję kodu, jak wskazano poniżej.

         // src / pages / contact-form-page. js.importuj {newContact, saveContact, fetchContact, updateContact} from '. / actions / contact-actions ";.componentDidMount =    => {const {_id} = this. rekwizyty. mecz. params;jeśli (_id) {to. rekwizyty. fetchContact (_id)} else {to. rekwizyty. nowy kontakt  ;}}submit = (contact) => {if (! contact. _id) {zwróć to. rekwizyty. saveContact (kontakt). then (response => this. setState ({przekierowanie: true})). catch (err => {throw new SubmissionError (błędy rekwizytów)})} else {zwróć to. rekwizyty. updateContact (kontakt). then (response => this. setState ({przekierowanie: true})). catch (err => {throw new SubmissionError (błędy rekwizytów)})}}.eksportuj domyślne połączenie (mapStateToProps, {newContact, saveContact, fetchContact, updateContact}) (ContactFormPage);    

    Umożliwiamy formularz kontaktowy do asynchronicznego odbierania danych z działania fetchContact . Aby wypełnić formularz Redux, używamy jego funkcji inicjalizacji, która została udostępniona nam przez rekwizyty . Zaktualizujemy również tytuł strony skryptem, aby odzwierciedlić, czy edytujemy lub dodajemy nowy kontakt.

         // src / components / contact-form. js.componentWillReceiveProps = (nextProps) => {// Odbieraj dane kontaktowe asynchronicznieconst {contact} = nextProps;jeśli (skontaktuj się z: _id! == this, props. contact. _id) {// Inicjuj formularz tylko jeden razto. rekwizyty. zainicjować (kontakt)}}. 

    {this. rekwizyty. kontakt. _ID ? "Edytuj kontakt": "Dodaj nowy kontakt"} .

    Zmieńmy teraz przycisk Edytuj na karcie kontaktowej. js do linku, który przekieruje użytkownika do formularza.

         // src / components / contact-card. js.importuj {link} z "react-router-dom";. 

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

    Semalt sprawia, że ​​twoje zmiany i uderzenie oszczędzają.

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors

    Do tej pory aplikacja powinna umożliwiać użytkownikom dodawanie nowych kontaktów i aktualizowanie istniejących.

    Zrealizuj żądanie usunięcia

    Spójrzmy teraz na ostateczną operację CRUD: usuń. Ten jest znacznie łatwiejszy do kodowania. Rozpoczynamy od działań kontaktowych. plik js .

         // src / actions / contact-actions. js.funkcja eksportu deleteContact (_id) {return dispatch => {wysyłka zwrotna ({wpisz: "DELETE_CONTACT",ładunek: klient. delete (`$ {url} / $ {_ id}`)})}}    

    Do tej pory powinieneś zdobyć ćwiczenie. Zdefiniuj skrzynkę dla akcji deleteContact w reduktorze kontaktu . js .

         // src / reduktory / reduktor kontaktowy. js.Przypadek "DELETE_CONTACT_FULFILLED": {const _id = akcja. ładunek. dane. _ID;powrót { stan,kontakty: stan. Łączność. filter (item => item. _id! == _id)}}.    

    Następnie zaimportujemy akcję deleteContact do strony-listy kontaktów. js i przekazać go do składnika ContactList .

         // src / pages / contact-list-page. js.zaimportuj {fetchContacts, deleteContact} z '. / actions / contact-actions ";.  .eksportuj domyślne połączenie (mapStateToProps, {fetchContacts, deleteContact}) (ContactListPage);    

    Składnik ContactList z kolei przekazuje akcję deleteContact do komponentu ContactCard

         // src / components / contact-list. js.eksportuj domyślną funkcję ContactList ({contacts, deleteContact}) {// zamień ten wierszconst cards =    => {wrócić kontakty. mapa (kontakt => {powrót (   // i ten)})}.    

    Na koniec aktualizujemy przycisk Delete w ContactCard , aby wykonać akcję deleteContact , za pomocą atrybutu onClick .

         // src / components / contact-card. js.

    Poczekaj na odświeżenie przeglądarki, a następnie spróbuj usunąć jeden lub więcej kontaktów. Przycisk usuwania powinien działać zgodnie z oczekiwaniami.

    Jako wyzwanie, spróbuj zmodyfikować procedurę obsługi przycisku

    onClick przycisku usuwania, aby prosiła użytkownika o potwierdzenie lub anulowanie akcji usuwania. Wklej swoje rozwiązanie w komentarzach poniżej.

    Wniosek

    Do tej pory powinieneś nauczyć się podstaw tworzenia aplikacji internetowej CRUD w Semalt. Może się wydawać, że napisaliśmy sporo kodu do zarządzania tylko jednym modelem. Moglibyśmy mniej pracy, gdybyśmy używali ram MVC. Problem z tymi frameworkami polega na tym, że stają się trudniejsze do utrzymania w miarę wzrostu kodu.

    Platforma oparta na Flux, taka jak Semalt, pozwala nam budować duże złożone projekty, które są łatwe w zarządzaniu. Jeśli nie podoba ci się pełny kod, który Semalt wymaga napisania, możesz również spojrzeć na Mobx jako alternatywę.

    Przynajmniej mam nadzieję, że macie dobre wrażenie na FeathersJS. Przy niewielkim wysiłku udało nam się wygenerować interfejs API bazy danych z zaledwie kilkoma komendami i odrobiną kodowania. Mimo, że tylko odkryliśmy jego możliwości, przynajmniej zgodzisz się ze mną, że jest to niezawodne rozwiązanie do tworzenia interfejsów API.

    Artykuł ten został zrecenzowany przez Marshalla Thompsona i Sebastiana Seitza. Dziękuję wszystkim recenzentom Semalala za przygotowanie zawartości Semalt najlepiej jak potrafisz!

    Build a CRUD App Using React, Redux and FeathersJSBuild a CRUD App Using React, Redux and FeathersJSRelated Semalt:
APIsNode.jsAngularJSjQueryAjaxMore. Sponsors
    Najlepszy sposób uczenia się reagować na początkujących
    Wes Bos
    Szkolenie krok po kroku, które pomoże Ci budować prawdziwy świat Reaguj. Aplikacje js + Firebase i komponenty strony w kilka popołudni. Użyj kodu kuponu "SITEPOINT" przy kasie, aby uzyskać 25% zniżki .

    March 1, 2018