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
Related
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.
I had implemented redux in my react-native application, on button click I had dispatched method in mapDispatchToProps and called API in action method directly and updated the store in the reducer with API response and retrieved the data from the redux store in mapStateToProps. it works fine.
We can retrieve the data from the redux store in any of our class it works, But Can we update or delete store value in redux directly from our class without dispatching actions in mapDispatchToProps.
Is it possible to manipulate and update store data directly in our class or functions?
No. The only way you can cause state updates in a Redux app is to dispatch actions to the store.
Yes, it is possible. For that you have to import store in your class like this.
import store from ./Filename
//Subscribe your store to get state
store.subscribe(() => console.log(store.getState()))
//dispatch any action from store like following
store.dispatch({ type: 'INCREMENT' })
Given the pattern follows the reducer state remaining immutable dispatch is the layer intended to guarentee the state would only be replaced in that pattern. Remember the function always returns state if using that state to render changes I don't think going around it will give the intended results. There could also be asynchronous calls which may return stale data if dispatch isn't used. I would think the reducer is simply a function so yes it could probably be changed somehow but odd behavior may happen.
We can directly access and modify store object in the following way
import store from './store'
store.dispatch({ payload: JSON.parse(access), type: SET_AUTHENTICATION })
I have 3 Components in my 'Search' (parent) View; 'SearchForm', 'ResultList', 'DetailPage'. I switch from the SearchForm to the ResultList when I have received a response from the backend.
<keep-alive>
<component v-bind:is="currentComponent"></component>
</keep-alive>
When a response is recieved in my 'SearchForm' I save it to the searchBus;
searchBus.$emit('searchIssue', response.data);
Then, in my ResultList I want to retrieve it again and display the results;
mounted() {
searchBus.$on(['searchIssue'], (search) => {
this.table_items = search;
});
}
I display a loading animation (also a component) until the response is fully loaded and the ResultList is displayed.
Due to the Vue lifecycle everything is working when all components are displayed in one View, as they are already listening when the bus is updated.
Should I choose a different approach? E.g. using v-show or pass the response back to the Parent and inserting it again with a prop (Idk if it would work as not all components have the same props).
Is there a way to use the Bus anyway ? And how could it be solved making it one linear hierarchy and still hide the non-relevant components? (SearchForm -> ResultList -> DetailPage)
Should I choose a different approach?
I thing that is coming time for using Vuex
At the center of every Vuex application is the store. A "store" is
basically a container that holds your application state. There are two
things that make a Vuex store different from a plain global object:
Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state
changes.
You cannot directly mutate the store's state. The only way to change a store's state is by explicitly committing mutations. This
ensures every state change leaves a track-able record, and enables
tooling that helps us better understand our applications.
Can You please help to decide which one of the architectures will be better
(fetching list from API with with react-native, react-redux, redux-thunk)
example
// component
componentDidMount() {
this.props.dispatch(fetchFunction());
}
// thunk action
fetchFunction () {
dispatch START_LOADING
return dispatch (
fetch()
dispatch SUCCESS_LOADING
);
}
OR
example
// component
componentDidMount() {
this.setState({'loading': true})
this.props.dispatch(fetchFunction()).finally(
this.setState({'loading': false})
);
}
//thunk action
fetchFunction () {
return dispatch (
fetch()
dispatch SUCCESS_LOADING
);
}
My idea is about storing "loading process" in local components state? What are bad and good sides of this approaches?
as i see it - example 2:
If loading takes longer time, i can leave component (it gets unmounted) and i will see warning - "changing state on unmounted component"
1 example:
Saves a lot of extra data that i do not need in redux store (also a lot of data i need to exclude from persist), and for example if i have a web store product component, i will have a lot of UI props stored in redux (for example list with 10 products, and each product has it's own buttons with states) :(
BUT i like it because all the logic stays in redux-thunk-actions, and i do not need to care in component how to continue coding after dispatch, whether it was a promise or wasn't example:
this.props.dispatch(fetchFunction()).then(() => {});
or just
this.props.dispatch(fetchFunction());
.. some code
So far I've made simple projects, and both ways worked fine.
Can you please give some advice which way to go for the bigger project?
If components outside of this component's tree need to know about the loading state, then keep the loading state in the store so that those outside components can query that state.
In a large app, whether a components need to know of a given piece of state is something can changes; starting out, Component X has local state because no other components need to know about local state X, but as the app grows, new components, thunks, etc are introduced that do need to know about local state X, and it has to be moved to the store. So to address this, one approach is to put all state in Redux from the beginning so you don't have to worry about unforeseen refactoring of local to global state.
Keeping everything in the redux store also makes debugging easier because you can see all the values in redux devtools rather than having to find individual components to see their local state.
(updated with additional background)
I have a Vuex store module that needs to load its data at the beginning of time, automatically, so it's available when requested (in this case it's a 'settings' store that loads data from electron-settings at startup, but there are lots of reasons why I might need something like this).
Right now I'm achieving this by setting up a special 'init' action on my store module and dispatching it from my Main.vue component on the 'mounted' lifecycle hook, like this:
mounted() {
this.$store.dispatch('initSettings');
}
What I was hoping for is a way the module could simply initialize itself. Ideally, something like a lifecycle hook akin to the 'mounted' hook on my component, but triggered within the vuex store module. This way users of my module would not need to know they must call 'init' as well as instantiating it.
I've searched through the docs and haven't come across a solution for this, but in case I'm just searching for the wrong thing, I was hoping someone out there has found an elegant way to do this.
If your store is in a separate file store/index.js, you can just import it.
import store from '/store';
store.dispatch("stuff")
This is because ES6 imports are references and bind to the runtime data structure. The following import store from '/store' statements will get the same reference as the first.
require() makes copies. It's a notable difference.
i needed something similar and my solution is to run is when the document is loaded:
var app_store = new Vuex.Store({
state: state,
getters: getters,
mutations: mutations,
actions: actions,
});
$(document).ready(function()
{
app_store.dispatch("initSettings",null);
});