how to get Product Code from current product service - spartacus-storefront

I'm new to spratacus, i want to get product code in type script.
product$: Observable = this.currentProductService.getProduct();
how to get product code? please help.

Your question could be rephrased to more specific:
How to get the value from the RxJs stream of data in Angular?
Answer:
It depends, where you want to access the value:
a) Most likely: you want to get it in the HTML template of your component. Then use Angular's async pipe:
<ng-container *ngIf="product$ | async as product">
<!-- use `product` variable here -->
</ng-container>
b) Or in your Typescript class (of component or service). Then you can subscribe to the observable to get the value. That said, it's not recommended approach, because then you need to manually dispose subscriptions to avoid memory leaks!
ngOnInit() {
this.sub = this.product$.subscribe(product => {
// use `product` variable here
})
}
/*...*/
ngOnDestroy() {
this.sub?.unsubscribe();
}
Referecnces
RxJs Observables are very powerful for managing asynchronous push-based streams of data. Angular team decided RxJs to be a first-class citizen. Spartacus also recommends using RxJs Observables and reactive approach. Read more here: https://angular.io/guide/observables .
That said, if you want to avoid observables as much as possible, you may be interested in this article https://dev.to/angular/how-to-avoid-observables-in-angular-273h

Related

For vue data, is it necessary to define data or is it just convention

For vue data, for every tutorials I have seen, it seems that data variables first defined as return value when creating vue instance like below:
app = createApp({
data() {
return {
someData: null,
}
},
}
I wonder if this practice is some way necessary or if it is just a convention, because I could simply define new data like this.someData2 in mounted or methods and it seems to work pretty much the same way.
I could simply define new data like this.someData2 in mounted or methods and it seems to work pretty much the same way ?
Answer is Yes, You can add a new property directly to this without including it in data. However, properties added this way will not be able to trigger reactive updates.
But we use the data option to declare reactive state of a component. The option value should be a function that returns an object. Vue will call the function when creating a new component instance, and wrap the returned object in its reactivity system.
Please do through this official documentation of Reactivity Fundamentals for better understanding.
the data option must be an function so every vue instance can maintain a separate copy of the return object,so it won't infect other instance

Use mobx or redux or with repository pattern and persistent local storage realm or sqlite?

Mobx and Redux will normally not persist any data. They will maintain a temporary global state while the app is running.
I know there are redux-persist and mobx-persist packages within both communities. But unfortunately these persisting solutions do not seem good at all. They only stringify or serialize a global state tree and persist it using some sort of key-value storage. Right?
The problem:
When such an app is open again, the stringified store will be parsed and structured back to its original data structure (JSON, for instance) and then fully loaded into the RAM memory. Am I right?
If yes, this is a problem. It is not good to always have a full "database" aka "global state" loaded in-memory. It will probably never be faster to filter data within a long array in my global state... compared to querying a table on SQLite, right?
I have been looking for some repository-like solution for persisting global state for either redux or mobx. I am yarning for some solution for persisting and querying data on some well-known mobile database like SQLite or others.
Any answers will be very much appreciated.
Indeed you can use repository pattern.
On your repository, you may have a save method.
save(group: GroupLocalStorageModel): Promise<boolean> {
let created;
this._localStorage.write(() => {
created = this._localStorage.create<GroupLocalStorageModel>("Group", group);
});
return Promise.resolve(true);
}
This method will literally save your entity to some local storage you set. In the example above, we are saving a group object to a Group collection which are like tables. We are using realm which is no-sql.
Once you have your repository, if you are using either redux or mobx, you will probably call your save method on your action. Both redux and mobx work with actions, right?
export const GroupStoreModel = types
.model("GroupStore")
.props({
groups: types.optional(types.array(GroupModel), []),
})
.extend(withEnvironment)
.actions((self) => {
return ({
_addGroupToStore(group: GroupLocalStorageModel) {
self.groups.push(group)
},
_deleteAllFromStore() {
self.groups.clear()
},
_addGroupsToStoreBatch: (groups: GroupLocalStorageModel[]) => {
self.groups.concat(groups);
},
})
})
/* Async actions */
.actions((self) => {
let groupRepository = self.environment.groupRepository;
return ({
addGroup(group: GroupLocalStorageModel) {
groupRepository.save(group).then(result => self._addGroupToStore(group))
},
getAllGroupsPaginated(page: number) {
groupRepository.getAllPaginated(page).then(groups => self._addGroupsToStoreBatch(groups));
},
deleteAll() {
groupRepository.deleteAll();
self._deleteAllFromStore();
}
})
})
In this example, we are using mobx-state-tree. And this addGroup action will update firstly our database, and then update also the global state.
We still want to use our global state so our views will be re-rendered automatically according to either connect for redux or observable for mobx.
See more informations here on the repository:
https://github.com/Hadajung/poc-react-native-database-example
AFAIK, there are two options for using sqlite with redux persist.
redux-persist-sqlite-storage: By maintainer's own word
By default redux-persist uses AsyncStorage as storage engine in react-native. This is a drop-in replacemet of AsyncStorage.
The library is inspired by react-native-sqlite-storage.
Please, remember, to use this, you need to install an additional package installed react-native-sqlite-storage
redux-persist-sqlite: By maintainer's own word
A redux-persist storage adapter that writes to sqlite.
This is adapted from https://github.com/prsn/redux-persist-sqlite-storage, but uses Node.js sqlite3 rather than react-native.
Great for Electron apps that are backed by Redux.
UPDATE: react-native-mmkv : This is developed by WeChat. As it says in its about section
An extremely fast key/value storage library for React Native. ~30x faster than AsyncStorage!
I'm not really sure what you need but if I understood you correctly you need to persist large amounts of data, and also to load that same data, but only in batches.
I believe that this kind of problem can be solved with a repository pattern and SOLID design principles.
You will need:
store class (mobx store) that holds your business logic.
repository class which is responsible for retrieving and persisting data.
The store gets the repository injected into it via the constructor.
Then when you call the initialize method on your store, it talks to the repository and retrieves the initial data. Now, initial data can be only a subset of all the data that is persisted. And you can implement some kind of paging on the store and repository, to retrieve data in batches as needed. Later you can call other methods to load and save additional data as needed.
pseudo code:
class Repository(){
initialize()// load the first batch
load(next 10 models)
save(data)
}
class Store{
constructor(repository)
initialize(){
repository.initialize()
}
load(){
repository.load()
}
save(){
repository.save()
}
}
Now your application data shouldn't be one giant object, rather it should consist of multiple stores, where each store is responsible for a part of the data. For example, you would have one store and repository for handling todos and another pair that handles address book contacts etc.
Addendum:
The reason the repository is injected into the store is so you could easily swap it for some other implementation (the store doesn't care how the data is persisted and retrieved) and also, unit testing is very easy.
You could also have a root store that would hold all other stores, so in essence you have your complete state in one place. So if you call serialize on the root store, it serializes all stores and returns one big object.
I think the best solution would be bloc hydrated or cubit hydrated package from flutter_bloc.
https://pub.dev/packages/hydrated_bloc
In background it uses Hive DB, very performant DB, and only keys are stored in memmory so it should not add huge bloat to the app like SQLite.
If you could make all you APP logic in blocks/cubits, then extra DB calls would be irelevant.

Most efficient way to filter an API response

I'm building a stock market overview app in Vue (+Vuex), getting market data from an API, then being updated every x seconds over websocket
Now i want to have a little section that shows "best performing markets"
I'm wondering what would be the most efficient way to handle this calculation.
(all in pseudocode)
1
(in vue component)
computed: {
getTopMarkets() {
filterTopMarkets(this.$store.state.markets)
}
}
2
(in vuex getter)
getters: {
topMarkets() {
return filterTopMarkets(state.markets)
}
}
#3
(other possibilities i am missing?)
is there a difference to the two approaches above (calculate in a computed property vs. calculate in a vuex getter)? is one faster than the other? better than the other? why?
thanks! :)
Both Vuex getters and computed component properties are JavaScript getters.
The long syntax of a computed is:
computed: {
yourComputed: {
get: function() { return expression }
}
}
equivalent of:
computed: {
yourComputed() { return expression }
}
and you can always define setters for computed:
computed: {
yourComputed: {
get: function() { return expression },
set: function(value) {
// dispatch an action or commit a mutation using value
}
}
}
This, combined with Vue's reactivity (or change detection mechanism) means that once they're run once, every time they're requested again Vue will serve the previously computed value - that's why they're called computed - (without actually re-running the code) until the moment any of the dynamic bits (references) change. When references change, the getter (whether it's a Vuex getter or a computed property) is rerun and all places where its referenced are notified (and those are re-run/re-rendered, in turn).
The only difference between the two cases is: Vuex getters are cached at store level, computed props are cached at component level.
In terms of both performance and change detection they're basically the same (internally they use the same mechanism).
Now, if you're only using this in one single component, the recommendation is not to use Vuex, as you'll have unnecessary additional boilerplate code around your data.
You're better off using a private store inside your component (either Vue.observable() or a Vue instance - before Vue.observable() was a thing, that was the way to create a basic Store without all the bells and whistles a Vuex store comes with).
Note: The mentioned alternatives allow you to expose the component's private store. If you don't need to expose it, don't bother: each component already has a private store: the data function (exposed to template). All you need to do is declare the reactive props upfront and from that point on the component will react to applied changes.
As already stated in the comment below your question, the choice here should not be based on code performance (as it's basically the same), but based on development and code management performance.
On how much your project will benefit from the order/structure Vuex comes with, in the long run:
how complex will your app get in time,
how many developers are/will be working on it and how well defined are the project's private conventions (if any)
how decoupled do you want/need data management and components to be)
how many iterations of this app are you expecting/foreseeing?
The more complex the project (codebase size, data structure complexity, app logic complexity, number of app iterations, number of developers), the more benefit you'll get from using Vuex, IMHO.

"Default Apollo Queries" VS "AsyncData" (Nuxt.js)

I'm building a site with Nuxt/Vue, and it's using a GraphQL backend API. We access this using the Apollo module for Nuxt.
In a page component, you can do this (I think this is called a Smart Query, but I'm not sure):
apollo: {
pages: {
query: pagesQuery,
update(data) {
return _get(data, "pageBy", {});
}
},
}
}
But you can also do the query like this I think, using the Nuxt asyncData hook:
asyncData(context) {
let client = context.app.apolloProvider.defaultClient;
client.query({query, variables})
.then(({ data }) => {
// do what you want with data
});
}
}
I'm not sure what the difference is between these two ways, and which is better. Does anyone know? I couldn't find an explanation in the docs anywhere.
Yeah, good question. The code you have shown at the top is indeed called a Smart Query. In fact
Each query declared in the apollo definition (that is, which doesn't
start with a $ char) in a component results in the creation of a smart
query object.
A nuxt project using the #nuxtjs/apollo module can use these out of the box. The beauty of the smart query is the options that it comes with and one of these is the 'prefetch' option. This, as it sounds, allows prefetching and is by default set to true. It can also accept a variables object or a function. You can see the docs here.
This means that the outcome of a smart query or an asyncData query will essentially be the same. They should be resolved in the same timeframe.
So why choose one or the other? This would probably be down to preference, but with all the options that a smart query allows you can do a lot more, and you can include subscriptions which might not be possible in asyncData.
More about smart queries here.

Flux without data caching?

Almost all examples of flux involve data cache on the client side however I don't think I would be able to do this for a lot of my application.
In the system I am thinking about using React/Flux, a single user can have 100's of thousands of the main piece of data we store (and 1 record probably has at least 75 data properties). Caching this much data on the client side seems like a bad idea and probably makes things more complex.
If I were not using Flux, I would just have a ORM like system that can talk to a REST API in which case a request like userRepository.getById(123) would always hit the API regardless if I requested that data in the last page. My idea is to just have the store have these methods.
Does Flux consider it bad that if I were to make request for data, that it always hit the API and never pulls data from a local cache instance? Can I use Flux in a way were a majority of the data retrieval requests are always going to hit an API?
The closest you can sanely get to no caching is to reset any store state to null or [] when an action requesting new data comes in. If you do this you must emit a change event, or else you invite race conditions.
As an alternative to flux, you can simply use promises and a simple mixin with an api to modify state. For example, with bluebird:
var promiseStateMixin = {
thenSetState: function(updates, initialUpdates){
// promisify setState
var setState = this.setState.bind(this);
var setStateP = function(changes){
return new Promise(function(resolve){
setState(changes, resolve);
});
};
// if we have initial updates, apply them and ensure the state change happens
return Promise.resolve(initialUpdates ? setStateP(initialUpdates) : null)
// wait for our main updates to resolve
.then(Promise.params(updates))
// apply our unwrapped updates
.then(function(updates){
return setStateP(updates);
}).bind(this);
}
};
And in your components:
handleRefreshClick: function(){
this.thenSetState(
// users is Promise<User[]>
{users: Api.Users.getAll(), loading: false},
// we can't do our own setState due to unlikely race conditions
// instead we supply our own here, but don't worry, the
// getAll request is already running
// this argument is optional
{users: [], loading: true}
).catch(function(error){
// the rejection reason for our getUsers promise
// `this` is our component instance here
error.users
});
}
Of course this doesn't prevent you from using flux when/where it makes sense in your application. For example, react-router is used in many many react projects, and it uses flux internally. React and related libraries/patters are designed to only help where desired, and never control how you write each component.
I think the biggest advantage of using Flux in this situation is that the rest of your app doesn't have to care that data is never cached, or that you're using a specific ORM system. As far as your components are concerned, data lives in stores, and data can be changed via actions. Your actions or stores can choose to always go to the API for data or cache some parts locally, but you still win by encapsulating this magic.