portaldacalheta.pt
  • Κύριος
  • Τάσεις
  • Κερδοφορία & Αποδοτικότητα
  • Επιστήμη Δεδομένων Και Βάσεις Δεδομένων
  • Διαδικασία Και Εργαλεία
Επιστήμη Δεδομένων Και Βάσεις Δεδομένων

Απλή ροή δεδομένων σε εφαρμογές React χρησιμοποιώντας Flux και Backbone: Ένας οδηγός με παραδείγματα



React.js είναι μια φανταστική βιβλιοθήκη. Μερικές φορές φαίνεται ότι είναι το καλύτερο πράγμα από τη φέτα Python. Το React είναι μόνο ένα μέρος της στοίβας εφαρμογών front-end, ωστόσο. Δεν έχει πολλά να προσφέρει όταν πρόκειται για τη διαχείριση δεδομένων και κατάστασης.

Το Facebook, οι κατασκευαστές του React, έχουν πρόσφερε κάποια καθοδήγηση εκεί με τη μορφή Ροή . Το Flux είναι μια «Αρχιτεκτονική Εφαρμογών» (όχι ένα πλαίσιο) που βασίζεται σε μονόδρομη ροή δεδομένων χρησιμοποιώντας React Views, Action Dispatcher και Stores. Το μοτίβο Flux επιλύει ορισμένα μεγάλα προβλήματα ενσωματώνοντας σημαντικές αρχές ελέγχου συμβάντων, οι οποίες καθιστούν τις εφαρμογές React πολύ πιο εύλογες για την ανάπτυξη, την ανάπτυξη και τη συντήρηση.



Εδώ, θα παρουσιάσω βασικά παραδείγματα ροής ροής ελέγχου, θα συζητήσω τι λείπει από τα καταστήματα και πώς να χρησιμοποιήσω τα μοντέλα και τις συλλογές Backbone για να καλύψουμε το κενό με τρόπο «συμβατό με Flux».



(Σημείωση: Χρησιμοποιώ το CoffeeScript στα παραδείγματα μου για ευκολία και συντομία. Οι προγραμματιστές που δεν χρησιμοποιούν CoffeeScript πρέπει να μπορούν να ακολουθούν και να αντιμετωπίζουν τα παραδείγματα ως ψευδοκώδικα.)



Εισαγωγή στο Flux του Facebook

Σπονδυλική στήλη είναι μια εξαιρετική και καλά ελεγμένη μικρή βιβλιοθήκη που περιλαμβάνει Προβολές, Μοντέλα, Συλλογές και Διαδρομές. Είναι ένα στην πραγματικότητα τυπική βιβλιοθήκη για δομημένες εφαρμογές front-end και έχει συζευχθεί με εφαρμογές React από την τελευταία που κυκλοφόρησε το 2013. Τα περισσότερα παραδείγματα του React εκτός του Facebook.com μέχρι στιγμής έχουν συμπεριλάβει αναφορές του Backbone που χρησιμοποιούνται παράλληλα.

Δυστυχώς, το να στηριχθούμε μόνο στο Backbone για να χειριστούμε ολόκληρη τη ροή εφαρμογών εκτός του React's Views παρουσιάζει ατυχείς επιπλοκές. Όταν άρχισα να δουλεύω για τον κωδικό εφαρμογής React-Backbone, τις «περίπλοκες αλυσίδες συμβάντων» που είχα Διαβάστε σχετικά δεν χρειάστηκε πολύς χρόνος για να οπίσθουν τα κεφάλια που μοιάζουν με υδρία. Η αποστολή συμβάντων από τη διεπαφή χρήστη στα μοντέλα και στη συνέχεια από το ένα μοντέλο στο άλλο και μετά ξανά, καθιστά δύσκολο να παρακολουθείτε ποιος άλλαζε ποιος, με ποια σειρά και γιατί.



Αυτό το σεμινάριο Flux θα δείξει πώς το μοτίβο Flux χειρίζεται αυτά τα προβλήματα με εντυπωσιακή ευκολία και απλότητα.

Μια επισκόπηση

Το σύνθημα της Flux είναι «μονόδρομη ροή δεδομένων». Εδώ είναι ένα πρακτικό διάγραμμα από το Έγγραφα ροής δείχνοντας πώς μοιάζει αυτή η ροή:



Το Facebook Flux χρησιμοποιεί ένα μοντέλο

Το σημαντικό κομμάτι είναι ότι τα πράγματα ρέουν από React --> Dispatcher --> Stores --> React.



Ας δούμε ποια είναι τα κύρια συστατικά και πώς συνδέονται:

Τα έγγραφα προσφέρουν επίσης αυτήν τη σημαντική προειδοποίηση:



Η ροή είναι περισσότερο μοτίβο παρά πλαίσιο, και δεν έχει σκληρές εξαρτήσεις. Ωστόσο, συχνά χρησιμοποιούμε το EventEmitter ως βάση για τα καταστήματα και το React για τις προβολές μας. Το ένα κομμάτι του Flux που δεν είναι άμεσα διαθέσιμο αλλού είναι το Dispatcher. Αυτή η ενότητα είναι διαθέσιμη εδώ για να ολοκληρώσετε την εργαλειοθήκη Flux.

Έτσι το Flux έχει τρία συστατικά:



  1. Προβολές (React = require('react'))
  2. Αποστολέας (Dispatcher = require('flux').Dispatcher)
  3. Καταστήματα (EventEmitter = require('events').EventEmitter)
    • (ή, όπως θα δούμε σύντομα, Backbone = require('backbone'))

Οι απόψεις

Δεν θα περιγράψω το React εδώ, αφού έχουν γραφτεί τόσα πολλά, εκτός από το να πω ότι το προτιμώ πολύ από το Angular. Σχεδόν ποτέ δεν νιώθω ταραγμένος κατά τη σύνταξη κώδικα React, σε αντίθεση με το Angular, αλλά φυσικά, οι απόψεις θα διαφέρουν.

Ο αποστολέας

Το Flux Dispatcher είναι ένα ενιαίο μέρος όπου χειρίζονται όλα τα συμβάντα που τροποποιούν τα καταστήματά σας. Για να το χρησιμοποιήσετε, έχετε κάθε κατάστημα register μία επιστροφή κλήσης για τη διαχείριση όλων των συμβάντων. Στη συνέχεια, όποτε θέλετε να τροποποιήσετε ένα κατάστημα, εσείς dispatch ένα γεγονός.

Όπως το React, το Dispatcher με θεωρεί καλή ιδέα, έχει εφαρμοστεί καλά. Για παράδειγμα, μια εφαρμογή που επιτρέπει στο χρήστη να προσθέσει στοιχεία σε μια λίστα υποχρεώσεων μπορεί να περιλαμβάνει τα εξής:

# in TodoDispatcher.coffee Dispatcher = require('flux').Dispatcher TodoDispatcher = new Dispatcher() # That's all it takes!. module.exports = TodoDispatcher # in TodoStore.coffee TodoDispatcher = require('./TodoDispatcher') TodoStore = {items: []} TodoStore.dispatchCallback = (payload) -> switch payload.actionType when 'add-item' TodoStore.items.push payload.item when 'delete-last-item' TodoStore.items.pop() TodoStore.dispatchToken = TodoDispatcher.registerCallback(TodoStore.dispatchCallback) module.exports = TodoStore # in ItemAddComponent.coffee TodoDispatcher = require('./TodoDispatcher') ItemAddComponent = React.createClass handleAddItem: -> # note: you're NOT just pushing directly to the store! # (the restriction of moving through the dispatcher # makes everything much more modular and maintainable) TodoDispatcher.dispatch actionType: 'add-item' item: 'hello world' render: -> React.DOM.button { onClick: @handleAddItem }, 'Add an Item!'

Αυτό καθιστά πολύ εύκολο να απαντήσετε σε δύο ερωτήσεις:

  1. Ε: Ποια είναι όλα τα συμβάντα που τροποποιούνται MyStore
    • Α: Απλώς ελέγξτε τις θήκες στο switch δήλωση σε MyStore.dispatchCallback.
  2. Ε: Ποιες είναι όλες οι πιθανές πηγές αυτού του συμβάντος;
    • Α: Απλώς αναζητήστε αυτό actionType.

Αυτό είναι πολύ πιο εύκολο από ό, τι, για παράδειγμα, η αναζήτηση MyModel.set και MyModel.save και MyCollection.add κλπ, όπου η παρακολούθηση των απαντήσεων σε αυτές τις βασικές ερωτήσεις γίνεται πολύ δύσκολη πολύ γρήγορα.

Το Dispatcher σάς επιτρέπει επίσης να εκτελείτε διαδοχικά callback με απλό, σύγχρονο τρόπο, χρησιμοποιώντας waitFor. Για παράδειγμα:

# in MessageStore.coffee MyDispatcher = require('./MyDispatcher') TodoStore = require('./TodoStore') MessageStore = {items: []} MessageStore.dispatchCallback = (payload) -> switch payload.actionType when 'add-item' # synchronous event flow! MyDispatcher.waitFor [TodoStore.dispatchToken] MessageStore.items.push 'You added an item! It was: ' + payload.item module.exports = MessageStore

Στην πράξη, σοκαρίστηκα όταν είδα πόσο καθαρότερος ήταν ο κώδικάς μου όταν χρησιμοποιούσα το Dispatcher για να τροποποιήσω τα καταστήματά μου, ακόμη και χωρίς τη χρήση waitFor.

Τα μαγαζιά

Έτσι ρέουν τα δεδομένα σε Αποθηκεύει μέσω του διεκπεραιωτή. Το έπιασα. Αλλά πώς ρέουν τα δεδομένα από τα Καταστήματα στις Προβολές (δηλαδή, Αντιδρούν); Όπως αναφέρεται στο Έγγραφα ροής :

οπτικό σχέδιο εναντίον γραφιστικής

Η [προβολή] ακούει συμβάντα που μεταδίδονται από τα καταστήματα στα οποία εξαρτάται.

Εντάξει ωραία. Ακριβώς όπως καταγράψαμε επιστροφές κλήσεων στα καταστήματά μας, καταχωρούμε επιστροφές κλήσεων στις προβολές μας (που είναι στοιχεία αντιδραστηρίων). Λέμε στο React να ξανα- render κάθε φορά που συμβαίνει μια αλλαγή στο Κατάστημα που μεταβιβάστηκε μέσω του props.

Για παράδειγμα:

# in TodoListComponent.coffee React = require('react') TodoListComponent = React.createClass componentDidMount: -> @props.TodoStore.addEventListener 'change', => @forceUpdate() , @ componentWillUnmount: -> # remove the callback render: -> # show the items in a list. React.DOM.ul {}, @props.TodoStore.items.map (item) -> React.DOM.li {}, item

Φοβερός!

Λοιπόν, πώς εκπέμπουμε αυτό 'change' Εκδήλωση? Λοιπόν, η Flux συνιστά τη χρήση EventEmitter. Από επίσημο παράδειγμα:

var MessageStore = merge(EventEmitter.prototype, { emitChange: function() { this.emit(CHANGE_EVENT); }, /** * @param {function} callback */ addChangeListener: function(callback) { this.on(CHANGE_EVENT, callback); }, get: function(id) { return _messages[id]; }, getAll: function() { return _messages; }, // etc...

Ακαθάριστο! Πρέπει να γράφω όλα αυτά μόνοι μου, κάθε φορά που θέλω ένα απλό κατάστημα; Τι πρέπει να χρησιμοποιώ κάθε φορά που έχω μια πληροφορία που θέλω να προβάλω; Πρέπει να υπάρχει ένας καλύτερος τρόπος!

Το κομμάτι που λείπει

Τα Μοντέλα και οι Συλλογές του Backbone έχουν ήδη όλα όσα φαίνεται να κάνουν τα Καταστήματα με βάση το EventEmitter της Flux.

Σας λέω να χρησιμοποιήσετε το Raw EventEmitter, η Flux συνιστά να δημιουργήσετε ξανά το 50-75% των Μοντέλων & Συλλογών του Backbone κάθε φορά που δημιουργείτε ένα κατάστημα. Η χρήση του EventEmitter για τα καταστήματά σας είναι σαν να χρησιμοποιείτε το γυμνό Node.js για τον διακομιστή σας, όταν υπάρχουν ήδη ενσωματωμένα μικροπλαίσια όπως το Express.js ή παρόμοιο για τη φροντίδα όλων των βασικών στοιχείων και του boilerplate.

Ακριβώς όπως το Express.js είναι ενσωματωμένο στο Node.js, τα μοντέλα και οι συλλογές του Backbone είναι ενσωματωμένα στο EventEmitter. Και έχει όλα όσα χρειάζεστε σχεδόν πάντα: Το Backbone εκπέμπει change εκδηλώσεις και έχει μεθόδους ερωτημάτων, getters και ρυθμιστές και τα πάντα. Επιπλέον, το Backbone's Τζέρεμι Άσκενας και ο στρατός του 230 συνεισφέροντες έκανε πολύ καλύτερη δουλειά σε όλα αυτά τα πράγματα από ό, τι μάλλον θα μπορούσα να κάνω.

Ως παράδειγμα για αυτό το φροντιστήριο Backbone, μετέτρεψα το παράδειγμα του MessageStore από πάνω σε μια έκδοση Backbone .

Είναι αντικειμενικά λιγότερος κώδικας (δεν χρειάζεται να αντιγράψετε εργασία) και είναι υποκειμενικά πιο σαφής και περιεκτική (για παράδειγμα, this.add(message) αντί για _messages[message.id] = message).

Ας χρησιμοποιήσουμε το Backbone για καταστήματα!

Το μοτίβο FluxBone: Flux Stores by Backbone

Αυτό το σεμινάριο είναι η βάση μιας προσέγγισης που έχω υπερηφανευτεί FluxBone , η αρχιτεκτονική Flux χρησιμοποιώντας το Backbone for Stores. Εδώ είναι το βασικό μοτίβο μιας αρχιτεκτονικής FluxBone:

  1. Τα καταστήματα είναι Instantiated Backbone Models ή Συλλογές, τα οποία έχουν καταχωρήσει μια επιστροφή κλήσης στο Dispatcher. Συνήθως, αυτό σημαίνει ότι είναι απλοί.
  2. Προβολή στοιχείων ποτέ άμεση τροποποίηση των καταστημάτων (για παράδειγμα, όχι .set()). Αντ 'αυτού, τα στοιχεία αποστέλλουν τις ενέργειες στον αποστολέα.
  3. Δείτε τα καταστήματα ερωτημάτων στοιχείων και δεσμεύστε τα συμβάντα τους για να ενεργοποιήσετε ενημερώσεις.

Αυτό το φροντιστήριο Backbone έχει σχεδιαστεί για να εξετάζει τον τρόπο συνεργασίας των Backbone και Flux σε εφαρμογές React.

Ας χρησιμοποιήσουμε παραδείγματα Backbone και Flux για να δούμε κάθε κομμάτι με τη σειρά:

1. Τα καταστήματα είναι Instantiated Backbone Models ή Συλλογές, τα οποία έχουν καταχωρήσει μια επιστροφή κλήσης στο Dispatcher.

# in TodoDispatcher.coffee Dispatcher = require('flux').Dispatcher TodoDispatcher = new Dispatcher() # That's all it takes! module.exports = TodoDispatcher # in stores/TodoStore.coffee Backbone = require('backbone') TodoDispatcher = require('../dispatcher') TodoItem = Backbone.Model.extend({}) TodoCollection = Backbone.Collection.extend model: TodoItem url: '/todo' # we register a callback with the Dispatcher on init. initialize: -> @dispatchToken = TodoDispatcher.register(@dispatchCallback) dispatchCallback: (payload) => switch payload.actionType # remove the Model instance from the Store. when 'todo-delete' @remove payload.todo when 'todo-add' @add payload.todo when 'todo-update' # do stuff... @add payload.todo, merge: true # ... etc # the Store is an instantiated Collection; a singleton. TodoStore = new TodoCollection() module.exports = TodoStore

2. Εξαρτήματα ποτέ άμεση τροποποίηση των καταστημάτων (για παράδειγμα, όχι .set()). Αντ 'αυτού, τα στοιχεία αποστέλλουν τις ενέργειες στον αποστολέα.

# components/TodoComponent.coffee React = require('react') TodoListComponent = React.createClass handleTodoDelete: -> # instead of removing the todo from the TodoStore directly, # we use the Dispatcher TodoDispatcher.dispatch actionType: 'todo-delete' todo: @props.todoItem # ... (see below) ... module.exports = TodoListComponent

3. Τα συστατικά ζητούν Stores και δεσμεύουν στα συμβάντα τους για να ενεργοποιούν ενημερώσεις.

# components/TodoComponent.coffee React = require('react') TodoListComponent = React.createClass handleTodoDelete: -> # instead of removing the todo from the TodoStore directly, # we use the dispatcher. #flux TodoDispatcher.dispatch actionType: 'todo-delete' todo: @props.todoItem # ... componentDidMount: -> # the Component binds to the Store's events @props.TodoStore.on 'add remove reset', => @forceUpdate() , @ componentWillUnmount: -> # turn off all events and callbacks that have this context @props.TodoStore.off null, null, this render: -> React.DOM.ul {}, @props.TodoStore.items.map (todoItem) -> # TODO: TodoItemComponent, which would bind to # `this.props.todoItem.on('change')` TodoItemComponent { todoItem: todoItem } module.exports = TodoListComponent

Έχω εφαρμόσει αυτήν την προσέγγιση Flux και Backbone στα δικά μου έργα, και μόλις ξανακάνω την εφαρμογή React για να χρησιμοποιήσω αυτό το μοτίβο, σχεδόν όλα τα άσχημα κομμάτια εξαφανίστηκαν. Ήταν λίγο θαυμαστό: ένα προς ένα, τα κομμάτια του κώδικα που με έκαναν να πνίξω τα δόντια μου αναζητώντας έναν καλύτερο τρόπο αντικαταστάθηκαν από λογική ροή. Και η ομαλότητα με την οποία φαίνεται να ενσωματώνεται το Backbone σε αυτό το μοτίβο είναι αξιοσημείωτη: Δεν αισθάνομαι ότι παλεύω με το Backbone, το Flux ή το React για να τα ταιριάξω σε μία μόνο εφαρμογή.

Παράδειγμα Mixin

Γράφοντας το this.on(...) και this.off(...) κωδικός κάθε φορά που προσθέτετε ένα FluxBone Store σε ένα στοιχείο μπορεί να γίνει λίγο παλιό.

Ακολουθεί ένα παράδειγμα React Mixin που, αν και εξαιρετικά αφελές, σίγουρα θα έκανε τη διαδικασία επανάληψης ακόμη πιο εύκολη:

# in FluxBoneMixin.coffee module.exports = (propName) -> componentDidMount: -> @props[propName].on 'all', => @forceUpdate() , @ componentWillUnmount: -> @props[propName].off 'all', => @forceUpdate() , @ # in HelloComponent.coffee React = require('react') UserStore = require('./stores/UserStore') TodoStore = require('./stores/TodoStore') FluxBoneMixin = require('./FluxBoneMixin') MyComponent = React.createClass mixins: [ FluxBoneMixin('UserStore'), FluxBoneMixin('TodoStore'), ] render: -> React.DOM.div {}, 'Hello, #{ @props.UserStore.get('name') }, you have #{ @props.TodoStore.length } things to do.' React.renderComponent( MyComponent { UserStore: UserStore TodoStore: TodoStore } , document.body.querySelector('.main') )

Συγχρονισμός με API Ιστού

Στο αρχικό διάγραμμα Flux, αλληλεπιδράτε με το Web API μόνο μέσω του ActionCreators, το οποίο απαιτεί απάντηση από το διακομιστή πριν από την αποστολή ενεργειών στο Dispatcher. Αυτό δεν κάθισε ποτέ μαζί μου. Δεν θα έπρεπε το Store να είναι το πρώτο που θα γνωρίζει τις αλλαγές, πριν από τον διακομιστή;

Επιλέγω να γυρίσω το τμήμα του διαγράμματος γύρω: τα καταστήματα αλληλεπιδρούν απευθείας με ένα RESTful CRUD API μέσω του Backbone's sync(). Αυτό είναι εξαιρετικά βολικό, τουλάχιστον εάν εργάζεστε με ένα πραγματικό RESTful CRUD API.

Η ακεραιότητα των δεδομένων διατηρείται χωρίς πρόβλημα. Όταν .set() μια νέα ιδιοκτησία, η change Το συμβάν πυροδοτεί μια εκ νέου απόδοση του React, εμφανίζοντας αισιόδοξα τα νέα δεδομένα. Όταν προσπαθείτε να .save() στον διακομιστή, το request το συμβάν σας ενημερώνει για την εμφάνιση ενός εικονιδίου φόρτωσης Όταν τα πράγματα περνούν, το sync το συμβάν σάς ενημερώνει για να καταργήσετε το εικονίδιο φόρτωσης ή το error το συμβάν σάς ενημερώνει για να κάνετε τα πράγματα κόκκινα. Μπορείτε να δείτε την έμπνευση εδώ .

Υπάρχει επίσης επικύρωση (και ένα αντίστοιχο συμβάν invalid event) για ένα πρώτο επίπεδο άμυνας, και ένα .fetch() μέθοδος για τη λήψη νέων πληροφοριών από το διακομιστή.

Υπάλληλος εναντίον ανεξάρτητου εργολάβου αριθμομηχανή

Για λιγότερο τυπικές εργασίες, η αλληλεπίδραση μέσω ActionCreators μπορεί να έχει μεγαλύτερη σημασία. Υποψιάζομαι ότι το Facebook δεν κάνει πολύ «απλό CRUD», οπότε δεν είναι περίεργο που δεν βάζουν τα καταστήματα πρώτα.

συμπέρασμα

Οι ομάδες μηχανικής στο Facebook έχουν κάνει εξαιρετική δουλειά ωθήστε το μπροστινό μέρος του ιστού προς τα εμπρός με Αντιδρώ , και η εισαγωγή του Flux δίνει μια ματιά σε μια ευρύτερη αρχιτεκτονική που πραγματικά κλιμακώνεται: όχι μόνο όσον αφορά την τεχνολογία, αλλά και τη μηχανική. Η έξυπνη και προσεκτική χρήση του Backbone (σύμφωνα με το παράδειγμα αυτού του σεμιναρίου) μπορεί να καλύψει τα κενά στο Flux, καθιστώντας απίστευτα εύκολο για οποιονδήποτε από τα ανεξάρτητα καταστήματα ενός ατόμου έως τις μεγάλες εταιρείες να δημιουργήσει και να διατηρήσει εντυπωσιακές εφαρμογές.

Σχετίζεται με: Πώς τα στοιχεία React κάνουν τη δοκιμή UI εύκολη

Πώς έφτιαξα έναν πλήρως λειτουργικό μετεωρολογικό σταθμό Arduino

Τεχνολογία

Πώς έφτιαξα έναν πλήρως λειτουργικό μετεωρολογικό σταθμό Arduino
Η ομάδα προϊόντων του ApeeScape

Η ομάδα προϊόντων του ApeeScape

Άνθρωποι Προϊόντων Και Ομάδες

Δημοφιλείς Αναρτήσεις
Σχεδιαστική στρατηγική - Ένας οδηγός για την τακτική σκέψη στο σχεδιασμό
Σχεδιαστική στρατηγική - Ένας οδηγός για την τακτική σκέψη στο σχεδιασμό
Γράψτε κώδικα για να ξαναγράψετε τον κωδικό σας: jscodeshift
Γράψτε κώδικα για να ξαναγράψετε τον κωδικό σας: jscodeshift
Κίνδυνος έναντι ανταμοιβής: Ένας οδηγός για την κατανόηση των εμπορευματοκιβωτίων λογισμικού
Κίνδυνος έναντι ανταμοιβής: Ένας οδηγός για την κατανόηση των εμπορευματοκιβωτίων λογισμικού
Το πάρτι δεν έχει τελειώσει: Μια βαθιά βουτιά στο γιατί οι μονόκεροι θα αναπηδήσουν το 2017
Το πάρτι δεν έχει τελειώσει: Μια βαθιά βουτιά στο γιατί οι μονόκεροι θα αναπηδήσουν το 2017
Επεξήγηση τεχνολογίας Blockchain: Ενίσχυση του Bitcoin
Επεξήγηση τεχνολογίας Blockchain: Ενίσχυση του Bitcoin
 
Πώς να επιλέξετε το καλύτερο πλαίσιο Front-End
Πώς να επιλέξετε το καλύτερο πλαίσιο Front-End
Η ηρεμία πριν την καταιγίδα
Η ηρεμία πριν την καταιγίδα
Οδηγός προγραμματιστή IOS: Από το Objective-C έως το Swift
Οδηγός προγραμματιστή IOS: Από το Objective-C έως το Swift
Πώς να διευκολύνετε την αλλαγή μέσω της ευέλικτης ηγεσίας των υπαλλήλων
Πώς να διευκολύνετε την αλλαγή μέσω της ευέλικτης ηγεσίας των υπαλλήλων
Το ApeeScape εγκαινιάζει το TopTracker, μια δωρεάν εφαρμογή παρακολούθησης χρόνου για ελεύθερους επαγγελματίες
Το ApeeScape εγκαινιάζει το TopTracker, μια δωρεάν εφαρμογή παρακολούθησης χρόνου για ελεύθερους επαγγελματίες
Δημοφιλείς Αναρτήσεις
  • πώς να λάβετε στοιχεία πιστωτικής κάρτας κάποιου
  • πώς να λάβετε στοιχεία πιστωτικής κάρτας κάποιου
  • πώς λειτουργεί η εφαρμογή shazam
  • συγχρονισμός (επιστήμη υπολογιστών)
  • διακοσμητικό μοτίβο συνδέεται συνήθως με
  • βέλτιστες πρακτικές UI/ux
Κατηγορίες
  • Τάσεις
  • Κερδοφορία & Αποδοτικότητα
  • Επιστήμη Δεδομένων Και Βάσεις Δεδομένων
  • Διαδικασία Και Εργαλεία
  • © 2022 | Ολα Τα Δικαιώματα Διατηρούνται

    portaldacalheta.pt