Εισαγωγή στο λειτουργικό Reactive προγραμματισμό στο Redux

Ας ξεκινήσουμε παίρνοντας τη βασική ιδέα για το τι είναι το "Reactive Programming":

Το Reactive Programming είναι ένα ασύγχρονο πρότυπο προγραμματισμού που αφορά τις ροές δεδομένων και τη διάδοση της αλλαγής.

- Βικιπαίδεια

Το ReactiveX ή το Rx είναι το πιο δημοφιλές API για αντιδραστικό προγραμματισμό. Είναι βασισμένο στις ιδεολογίες του παρατηρήσιμου προτύπου, του μοτίβου Iterator και του λειτουργικού προγραμματισμού. Το Rx έχει βιβλιοθήκες για διαφορετικές γλώσσες, αλλά θα χρησιμοποιούμε το RxJS.

Το Rx βασίζεται σε παρατηρήσιμα , παρατηρητές και χειριστές

Ο Παρατηρητής εγγράφεται ουσιαστικά σε ένα Παρατηρήσιμο.

Στη συνέχεια, το Observable εκπέμπει ροές δεδομένων στα οποία ο Παρατηρητής ακούει και αντιδρά, θέτοντας σε κίνηση μια αλυσίδα λειτουργιών στη ροή δεδομένων. Η πραγματική ισχύς προέρχεται από χειριστές ή «Reactive Extensions» (εξ ου και ο όρος Rx) .

Οι χειριστές σας επιτρέπουν να μετασχηματίζετε, να συνδυάζετε, να χειρίζεστε και να εργάζεστε με τις ακολουθίες των αντικειμένων που εκπέμπονται από το Observables.

Εάν δεν είστε εξοικειωμένοι με το Rx, ίσως δυσκολευτείτε να κατανοήσετε και να χρησιμοποιήσετε το Redux-Observable. Προτείνω λοιπόν να βρώσετε πρώτα τα χέρια σας με το Rx!

Τώρα για χρήση του RxJS με το Redux.

Redux-παρατηρήσιμο

Το Redux-Observable είναι ένα ενδιάμεσο λογισμικό βασισμένο σε RxJS για το Redux

Αυτό έχει να πει τα Έγγραφα Redux σχετικά με το middleware στο Redux:

Το Middleware παρέχει ένα σημείο επέκτασης τρίτου μέρους μεταξύ της αποστολής μιας ενέργειας και της στιγμής που φτάνει στον μειωτή.

Το μεσαίο λογισμικό Redux μπορεί να χρησιμοποιηθεί για καταγραφή, αναφορές σφαλμάτων, συνομιλία με ασύγχρονο API, δρομολόγηση και άλλα. Ή μπορούμε να πούμε ανεπιθύμητες ενέργειες γενικά.

Πώς λοιπόν το Redux-Observable κάνει όλα αυτά;

Μέσα στα Έπη. Τα έπη είναι το βασικό πρωτόγονο του Redux-Observable. Ένα έπος είναι απλώς μια απλή λειτουργία που παίρνει μια ενέργεια και στη συνέχεια επιστρέφει μια άλλη ενέργεια. Ενέργεια In → Action Out . Επομένως, οι ενέργειες αντιμετωπίζονται ως ροές.

Κάθε ενέργεια που αποστέλλεται σε οποιοδήποτε συστατικό του React θα περάσει από τέτοιες λειτουργίες (Epics) ως ροή.

Ας δούμε τι είναι ένα απλό Epic που παίρνει action'PING’και επιστρέφει μια νέαaction'PONG’ εμφάνιση:

const pingEpic = action$ => action$.filter(action => action.type === 'PING') .mapTo({ type: 'PONG' })

Το $μετά actionχρησιμοποιείται για να δείξει ότι αυτές οι μεταβλητές αναφέρονται σε ροές. Έχουμε λοιπόν ένα ρεύμα ενεργειών που περνούν στο Epic στο οποίο χρησιμοποιήσαμε τον filterχειριστή του RxJS.

Αυτός ο τελεστής φίλτρου φιλτράρει όλες τις ενέργειες που δεν είναι typePING! Επομένως, το Epic pingEpicασχολείται μόνο με το χειρισμό ενεργειών του type‘PING’. Τέλος, αυτό action‘PING’χαρτογραφείται σε έναν νέο actionαπό type‘PONG’τον βασικό κανόνα του Epics: Action In → Action Out .

Δεδομένου ότι κάθε επικό ασχολείται μόνο με έναν συγκεκριμένο τύπο ενέργειας, έχουμε έναν ειδικό χειριστή για το action$(stream) για να φιλτράρετε τις ανεπιθύμητες ενέργειες από τη ροή. Αυτός ο χειριστής είναι ο ofType()χειριστής.

Ξαναγράφοντας το προηγούμενο Epic χρησιμοποιώντας ofType:

const pingEpic = action$ => action$.ofType('PING') .mapTo({ type: 'PONG' })

Αν θέλετε επικό σας για να επιτρέψει σε περισσότερους από έναν τύπους δράσης, ο ofType()φορέας μπορεί να πάρει οποιοδήποτε αριθμό των επιχειρημάτων αρέσει τόσο: ofType(type1, type2, type3,...).

Εισαγωγή στις λεπτομέρειες του τρόπου λειτουργίας των Epics

Μπορεί να πιστεύετε ότι η δράση «PING» έρχεται απλά και καταναλώνεται από αυτό το έπος. Αυτή δεν είναι η περίπτωση. Υπάρχουν δύο πράγματα που πρέπει να θυμάστε πάντα:

  1. Κάθε ενέργεια πηγαίνει πάντα στον μειωτή πρώτα
  2. Μόνο μετά από αυτήν είναι η δράση που έλαβε το έπος

Επομένως, ο κύκλος Redux λειτουργεί κανονικά όπως θα έπρεπε.

Το action‘PING’φθάνει πρώτα στον μειωτή και στη συνέχεια λαμβάνεται από το Epic, στη συνέχεια αλλάζει σε νέο action‘PONG’που αποστέλλεται στον μειωτή.

Μπορούμε ακόμη και να αποκτήσουμε πρόσβαση στην κατάσταση του καταστήματος μέσα σε ένα Epic, επειδή το δεύτερο επιχείρημα ενός Epic είναι μια ελαφριά έκδοση του Redux Store! Δες παρακάτω:

const myEpic = (action$, store) =>

Μπορούμε απλώς να ll store.getStat(e) και να αποκτήσουμε πρόσβαση στην κατάσταση εντός του Epics.

Αλυσίδα χειριστή

Μεταξύ της λήψης μιας ενέργειας και της αποστολής μιας νέας, μπορούμε να κάνουμε κάθε είδους ανεπιθύμητες ενέργειες που θέλουμε, όπως κλήσεις AJAX, πρίζες web, χρονοδιακόπτες και ούτω καθεξής. Αυτό γίνεται χρησιμοποιώντας τους πολυάριθμους χειριστές που παρέχονται από τη Rx.

Αυτοί οι τελεστές Rx σάς επιτρέπουν να συνθέσετε ασύγχρονες αλληλουχίες μαζί με δηλωτικό τρόπο με όλα τα οφέλη απόδοσης των επιστροφών κλήσεων αλλά χωρίς τα μειονεκτήματα των χειριστών επανάκλησης επένδυσης που σχετίζονται συνήθως με ασύγχρονα συστήματα.

Παίρνουμε τα οφέλη των επιστροφών, χωρίς αυτό το περίφημο «callback hell».

Δείτε πώς μπορούμε να αξιοποιήσουμε τη δύναμη των χειριστών παρακάτω.

Μια κοινή υπόθεση χρήσης

Assume that we want to search for a word with something like a dictionary API using text entered by the user in real-time. We’re basically dealing with storing (in the Redux store) and displaying the results from the API call. We would also like to debounce the API call so that the API is called within, say, 1 second of when the user stops typing.

This is how it’ll be done using Epic and RxJS operators:

const search = (action$, store) => action$.ofType('SEARCH') .debounceTime(1000) .mergeMap(action => ajax.getJSON(`//someapi/words/${action.payload}`) .map(payload => ({ type: 'SET_RESULTS', payload })) .catch(payload => Observable.of({type: 'API_ERROR', payload})) )

Too much to handle?! Don’t worry, let’s break that down.

The epic is getting a stream of actions all oftype‘SEARCH’. Since the user is continuously typing, the payload of every incoming action (action.payload) contains the updated search string.

The operator debounceTime() is used to filter out some of the actions in the stream except the last one. It basically passes an action through it only if 1 second has elapsed without it receiving another action or observable.

We then make the AJAX request, mapping the results to another action 'set_RESULTS' which takes the response data (payload) to the reducer, which is the Action Out part.

Any API errors are caught using the catch operator. A new action is emitted with the error details and later displays a toaster with the error message.

Notice how the catch is inside the mergeMap() and after the AJAX request? This is because the mergeMap() creates a chain that is isolated. Otherwise the error would reach ofType() and will terminate our Epic. If that happens, the Epic will stop listening to any action in the future!

We can use traditional promises for AJAX requests as well. However, they have this inherent problem of not being able to get cancelled. So another important use case for using Epics is AJAX cancellation.

We use the takeUntil operator to handle this issue. This is done just like we used that catch operator inside mergeMap and after the AJAX request.

This is because takeUntil must stop the current AJAX request and not the entire Epic! Therefore, isolating operator chains is important here as well.

Debouncing, throttling, filtering, AJAX cancellation and others, are just the tip of the iceberg. We have a myriad of operators at our disposal, making difficult use-cases trivial to solve. Using these operators, you can get as creative as your imagination allows you to be! Functional Reactive Programming (FRP) is elegant in its own way.

My focus for this article was on the explanation part of FRP in Redux using Redux-Observable. For setting up Redux-Observable in React+Redux, refer to the official docs — its very well documented, detailed, and easy-breezy.

Be sure to check out my other article on Redux which explores the best practice for creating reducers:

Reducing the Reducer Boilerplate With createReducer()

First, a quick recap of what reducers in Redux are:medium.freecodecamp.org

Θέλετε να βελτιώσετε τα βασικά σας JavaScript; Διαβάστε τα παρακάτω:

Λειτουργίες JavaScript ES6: Τα καλά μέρη

Το ES6 προσφέρει μερικές δροσερές νέες λειτουργικές δυνατότητες που κάνουν τον προγραμματισμό σε JavaScript πολύ πιο ευέλικτο. Ας μιλήσουμε για… medium.freecodecamp.org Ένας οδηγός για ανύψωση μεταβλητών JavaScript; με let and const

Ν προγραμματιστές Νέες το JavaScript συχνά έχουν έναν σκληρό χρόνο κατανόηση της μοναδική συμπεριφορά της μεταβλητής / συνάρτησης hoisting.m edium.freecodecamp.org Λειτουργία ανύψωσης & Ανέλκυση ερωτήσεις συνέντευξης

Αυτό είναι ένα μέρος 2 για το προηγούμενο άρθρο μου σχετικά με την ανύψωση μεταβλητών με τίτλο «Ένας οδηγός ανύψωσης μεταβλητών JavaScript; με… m edium.freecodecamp.org

Ειρήνη ✌️