How to share state between StencilJS components - stenciljs

I would like to share state between my StencilJS components. So I checked out the Redux implementation which they promote on their API site. It does something like
#Prop({ context: "store" }) store: Store;
But now I just red the BREAKING_CHANGES, which described that using context is deprecated. I actually liked using context but if this is deprecated, how can I share state between my components. I'm not really looking forward to pass everything from parent to child to etc.

The context API, even though deprecated, will still work, at least until the #stencil/redux package has been updated.
If you're looking for a simple alternative for global state, you should have a look at #stencil/store (https://github.com/manucorporat/stencil-store/tree/master/packages/stencil-store). It allows you to create a store with createStore(initalState) and returns a state reference which you can just import and reference in your component. When the store's state changes, the library will take care of triggering an update of your component.

Related

Vue.js initialize custom component only once and use it as base for multiple views

I created a vue component based on MapBox, which is restricted in initializations before it costs money and that is perfectly fine. But I want to reduce reinitializations of my map component for their and my sake.
That's why I thought if it is possible to define the component once, pass in some properties and then handle the state via vuex.
Right now, I'd have to import my component and add the data like this:
<Map
:sources="geoData.sources"
:layers="geoData.layers"
:mapOptions="mapOptions"
:componentOptions="{ drawingEnabled: toggleMapDrawing, activeLayers: activeMapLayers, activeMarkerGroups: [] }"
#loaded="onMapLoaded" #selectedMarkers="onSelectedObjects"/>
The componentOptions are being watched, so the component changes its state accordingly.
My ideas/approaches so far were the following:
I thought about adding the snippet above to the root vue file, but that won't help since I want to place the map component dynamically and not statically before the rest of the page content.
Passing a rendered vue component into a variable and appending that later would be a bit too hacky, if it is even possible.
Using slots, but from what I've seen in the docs, it's not possible to use a slotted component from a parent component in a child like this.
The best idea that has come to my mind was to define the actual MapBox variable (which I suppose triggers the API for initialization) and then save that globally using the store or something. But since that will immediately append the component to a DOM element that will be specified in the options, so I'd have to store that somehow, too.
The initialization of the map happens in the mounted hook of the component and looks like this:
const baseOptions = {
accessToken: process.env.MAPBOX_TOKEN,
container: 'map',
style: process.env.MAPBOX_STYLE_URL,
minZoom: 10,
maxZoom: 20,
zoom: 13,
bearing: 150,
pitch: 50
}
this.map = new mapboxgl.Map(Object.assign(baseOptions, this.mapOptions))
if (!this.map) { throw new Error('Could not create map. Make sure the token is valid.') }
I might be wrong, maybe there's a better way or maybe this whole idea might be garbage, but hopefully it's not. Also please note that I'm not using the vue-mapbox module, because it's not being maintained anymore.
I'm thankful for any ideas and hints :)
You may use <KeepAlive>, a built-in component available in both Vue2 (docs) and Vue3 (docs).
Basically it ensures that a component tagged with keep-alive will only be mounted once. So in your case, you can place the map wherever you want, and the Map will only be initialized once in its mounted hook.
If you need to utilize the moment that your Map gets "focused" or "activated" so to say, then you can utilize the activated and deactivated hooks.
Why you cannot use KeepAlive.
There is an obvious and logical limitation. As long as the parent is alive and mounted, the component's children that are being kept-alive will stay alive. But if the keep-alive component's parent gets unmounted, then all the children will be unmounted aswell even if they were being kept alive. This is all very obvious but I just felt like pointing it out.
Solution
So, in your use case, you want a component (the <Map> component) to be globally kept-alive after its first initialization. I suggest you cache the map element itself and store it in the store. Then on every <Map> component onBeforeMount (Composition API) or beforeMount (Options API) hook, manually check if the element is cached, if it is then insert the cached map from the store, otherwise initialize the map.

How to integrate Mobx State Tree with Vue JS?

I am building application on Vue and want to use Mobx State Tree as a store management library. I trying and finally made something working, but seems to it isn't work properly.
First, I have Changer component that change store via action. Works perfectly.
Second, I have Test component that tryes to react on store changes via passed props. Works fine only if I return prop via method.
Third, I have BlindTest component that tryes to react on store changes via this.$store itself and via state prop. Works fine only if I provide immutable snapshot as a state via function.
This is incorrect and strange behavior. Components updates only if props was changed, not if state was changed. Why?
Also I used mobx-vue library from official mobxjs repository for bindings between mobx and vue.
There is sandbox with demo application: https://codesandbox.io/embed/vue-template-ouq7r
Is there any way to connect MST and Vue properly?
You can use the official library: https://github.com/mobxjs/mobx-vue

Global vuex watchers

I have a Vuex store feeding many Vue components in a somewhat large web app. I would like to be able to watch Vuex states or getters for logging purposes. However, I want to be able to watch them 'globally', i.e. without relying on any particular Vue component. This rules out tricks like
//aComponent.vue
watch:{ '$store.state.data'(value, oldValue) { /*do something here*/ }}
and
//App.vue
created() {
this.$store.watch((state) => state.watchedState) => {/*do something here*/ })
}
Instead, I am looking for a way to watch my Vuex states or getters directly from the module where the store is defined, so that whenever a state changes, I can call a function passing it as arguments the old state and the new state, so as to write the change into a database (ideally the change itself would be detected automatically, as in Vue's watch(new,old) {...}.
I suppose I should use Vuex native method store.watch() for this purpose. But so far I have not be able to invoke it from the store module, as desired.
Any clue? Or did I miss something and what I am trying to do would be just as efficiently done with a different technique?
For watching mutations you have this options.
You can subscribe to a store and get notified by mutation after it happens.
store.subscribe( (mutation, state) => {
})
You can achieve this in a couple of ways:
use subscribe on the store you create by hand, most likely in main.js
create a plugin that gets appended to each instance of a store and again subscribe to it
just use the vuex official plugin for logging
For watching getters you probably need to monkey patch the getters property by hand.
Then again, if you want to watch what happens with vuex during development you can use vuejs tools

Can I use global variables in React Native to store user information?

I have an application that has hundreds of screens. I usually pass the variables from parent to child between the components with props. I find it very uncomfortable to pass the array with the user information hundreds of times.
I am testing the global variables of react native. Does it have any danger to use a global variable to save user information and modify it within the components?
I have searched for documentation and nothing is said. I know it's not correct in react, but it works wonders for me.
Any recommendation?
If that global variable is a constant or it's value doesn't effect rendering of components then you are good to use it as global variable or async storage.
But if it's value is changing and affecting the rendering of component then I highly recommend you to store that value as state and to make it global you can either use
1) Context api (https://reactjs.org/docs/context.html)
2) Or Redux

Vue Single page app Router, what happens with the components when we change route?

Let's suppose I have a component called FirstPage, which is my default route, now FirstPage triggers an asynchronous call, with the help of an action of the vuex store, to be made each minute to a backend Api (it's triggered when the component is loaded as a route), now let's say I go to an about route that goes to an About component, is FirstPage still making the calls?
Edit:
I'm not developing an app with that yet, so I can't provide examples.
It's on my interest to know the behavior in these cases of the router, because whenever I change the route I would want to stop making the constant calls (as they won't be necessary).
The reason is that Depending on this I'd have to switch tooling for a project I have in mind.
In general, a component's instance will be destroyed when you navigate away from it. However, there are two exceptions to this ..
When you use routes with params. From the Vue Router docs
One thing to note when using routes with params is that when the user navigates from /user/foo to /user/bar, the same component instance will be reused. Since both routes render the same component, this is more efficient than destroying the old instance and then creating a new one. However, this also means that the lifecycle hooks of the component will not be called.
When you wrap your router-view component within a keep-alive element. Since the <router-view> is essentially a dynamic component.
Generally Vue does a very good job of housekeeping and cleaning up after a component's instance when it gets destroyed. But sometimes you'll have to do some manual cleanup, especially if you use some kind of external library. This is usually handled in the beforeDestroy hook of an instance's lifecycle.
In normal conditions, any logic/scripts/etc done at creation inside said component will be "purged" on the on destroy/close hooks (not only pertinent to vue but seen in lots of other tools), if there is a need to persist something then it should be in a higher scope (or other solution)
Any script written for the respective component only runs if the component is rendered in page. Once you go to about component replacing the previous component then previous script wont run.
you can make a parent component with a router-view and load in your page you always want to get loaded, so your FirstPage component, but this component should just have logic behind it, and no html because otherwise you will always see that rendered. Router-view the page you want to display the real html and stuff. I hope you get the idea, if not i could make an example for you. Goodluck.