I have an important task to do while data is computed within a vuex mapState. I need to call this vue method countAlerts every time data is changed; to do that the computed property needs to call that method but this scope has no vue methods when it is used insight vuex mapState.
export default {
name: "Alerts",
methods: {
countAlerts(data, period) {
/// DO SOMETHING, THEN RETURN DATA
return data;
}
},
computed: {
...mapState({
foundation: state => state.insights.foundation,
insights: state => {
return state.insights.list.filter(al => {
switch (state.insights.foundation.period) {
case "daily":
// ====>> NEED TO CALL METHOD HERE <<=====
al = this.countAlerts(al, "daily");
if (
al.threeDayUp ||
al.threeDayDown ||
al.greatDayUp ||
al.greatDayDown
) {
return al;
}
break;
/// MORE CODE ABOVE
}
});
}
})
}
};
this is bound to the component's contex when you define computed props as functions.
From the docs:
// to access local state with `this`, a normal function must be used
countPlusLocalState (state) {
return state.count + this.localCount
}
Related
I want to update my data values with values in the store.js, how it is possible? below code gave me blank page error.
App.vue
data() {
return {
storeState: store.state,
Counter: this.storeState.Counter,
}
}
store.js
export const store = {
state: {
Counter: 1,
}
CounterUpdater(value) {
this.state.Counter = (value);
},
}
You can't refer to a data property (storeState) inside the data option that way, and you don't need it anyway. You should use computeds to sync component values with Vuex values. Remove both data values:
computed: {
Counter() {
return this.$store.state.Counter;
}
}
Or use mapState:
import { mapState } from 'vuex'
computed: {
Counter() {
...mapState(['Counter'])
}
}
Also make sure your store mutation is inside mutations and using the proper syntax:
state: {
Counter: 1
},
mutations: {
CounterUpdater(state, value) {
state.Counter = value;
}
}
It's also recommended to name your variables according to camelCase convention (i.e. means lowercase counter in your code)
How to instantaneously update changes committed to vuex store in the ui of another component?
following is the vuex store module of a component
const { property } = require("lodash")
export default {
state: {
data: [
{id: 1, name: 'Angular', status: 'active'},
{id: 2, name: 'React', status: 'active'},
{id: 3, name: 'Vue', status: 'inactive'},
]
},
mutations: {
UPDATE_ITEM(state, payload) {
const item = state.data.find(item => _.isEqual(item, payload.item))
Object.assign(item, payload.status);
},
},
actions: {
updateItem({ commit }, payload) {
commit("UPDATE_ITEM", payload);
},
},
getters: {
getData: (state) => state.data,
getMappedStatus: (state) => state.data.map(data => data.status)
},
};
this is how I get mapped status in component 1
computed: {
getMappedStatus() {
return this.$store.geters.getMappedStatus
}
}
and inside the ui of component 1
<ul>
<li v-for="item in getMappedStatus>{{item}} </li>
</ul>
from another component 2 I'm updating the changes as the user inputs the status:
onStatusChanges(item, status) {
this.$store.dispatch("updateItem", {
item, status
});
},
But the problem is that even though the state is getting updated the ui is not getting updated.But
(inside component 1)
I think it is because of the computed property. ... not sure.
How can I implement something like and observable or something reactive so that the getMappedStatus computed property in component 1 will get updated automatically as action is dispatched from component 2.
NOTE Both components come under the same vuex store module
If this was in angular/ngrx I would subscribe to the selectors inside the component 1 and I would get instantaneously the changes. even If I subscribe to the event inside the onInit() method or constructor() and do a console.log() the changes from the other component will be reflected instantaneously.
But this is not happening with vuex.
How can I achieve that:?
or is there a way to trigger the updation of the getMappedStatus computed property inside component 1 as soon as changes occurs from component 2:
computed: {
getMappedStatus() {
return this.$store.geters.getMappedStatus
}
}
so that the ui of component 1 updates instantaneously.
We can think of getters as computed properties for stores. Like computed properties, a getter's result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed so that simply means if component1 mutates the state in vuex store and component2 uses that property from the store it will automatically update in all components using it.
Online IDE - Live Demo Here
Vuex Store
const store = new Vuex.Store({
state: {
name: 'mex'
},
mutations: {
mutateName(state, value) {
state.name = value;
}
},
actions: {
updateName(context, payload) {
context.commit('mutateName', payload.name);
}
},
getters: {
getName(state) {
return state.name;
}
}
});
The changeName method when fired will dispatch updateName action which will update the name and all the components will update accordingly because it's reactive.
Then In Any Component
computed:{
name() {
return this.$store.getters.getName
}
},
methods: {
changeName: function () {
this.$store.dispatch('updateName', { name: 'mexxxxx'});
}
}
You need to return something from getMappedStatus
computed: {
getMappedStatus() {
return this.$store.geters.getMappedStatus
}
}
...without a return statement the this.$store.geters.getMappedStatus is just an expression and your computed property always returns undefined (because JS functions without return always return undefined)
At the moment, I learn how to use react context API.
I have a react Provider class, with some state data and functions in the value={}. How can I access a function inside this value from another function inside this value?
So, the function1() is called by a child component. When the state change is finished, I want to call the function2() and access the new state.
Is it possible in react to get something like this?:
class Provider extends Component {
state = {
foo: 'bar'
}
render() {
return() {
<Context.Provider value={{
state: this.state,
function1: () => {
this.setState({ foo: 'changed' }, () => {
// HERE I WANT TO CALL THE NEXT FUNCTION IN THIS VALUE
this.function2()
});
},
function2: () => {
// called by function1 after state change
console.log(this.state)
}
}}>
{ this.props.children }
</Context.Provider>
}
}
}
If I try to run this, and fire the function1() from the child, it gives me
TypeError: _this2.function2() is not a function
I don't understand, why it is trying to access a _this2 variable, because I defined it to access this.function2().
Is it just not possible to do what I want in react? You might say, why the function2() is an extra function, and why I don't add the code in the end of the function1(). It's because the function2() has to be a independent accessable function.
Can anyone help me? Thanks!
What you can try to do is this:-
class Provider extends Component {
state = {
foo: 'bar'
}
an_independent_function() {
console.log(this.state);
}
render() {
return() {
<Context.Provider value={{
state: this.state,
function1: () => {
this.setState({ foo: 'changed' }, () => {
// HERE I WANT TO CALL THE NEXT FUNCTION IN THIS VALUE
this.an_independent_function();
});
},
function2: this.an_independent_function.bind(this)
}}>
{ this.props.children }
</Context.Provider>
}
}
}
I need access to user editable state from two or more reducers. Is there a way to access state controlled by another reducer without passing it to the reducer through the action's payload? I want to avoid having every action send user settings to reducers.
State
{
userSettings: {
someSetting: 5
},
reducer1State: {
someValue: 10 // computed with userSettings.someSetting
},
reducer2State: {
someOtherValue: 20 // computed with userSettings.someSetting
}
}
From the reducer1 I would like to get at userSettings.someSetting using something like the following:
function update(state={}, action) {
if (action.type === constants.REDUCER_1.CALCULATE) {
return _.assign({}, state, {
someValue: 2 * GETSTATE().userSettings.someSetting
});
}
...
I do not want to have to send userSettings from the action like this:
export function calculate(userSettings) {
return {
type: constants.REDUCER_1.CALCULATE,
userSettings: userSettings
};
}
One of the golden rules of Redux is that you should try to avoid putting data into state if it can be calculated from other state, as it increases likelihood of getting data that is out-of-sync, e.g. the infamous unread-messages counter that tells you that you have unread messages when you really don't.
Instead of having that logic in your reducer, you can use Reselect to create memoized selectors that you use in your connectStateToProps function, to get your derived data, e.g. something along the line of this:
const getSomeSettings = state => state.userSettings.someSetting;
const getMultiplier = state => state.reducer1.multiplier;
const getSomeValue = createSelector([getSomeSettings, getMultiplier],
(someSetting, multiplier) => {
});
const mapStateToProps(state) => {
return {
someValue: getSomeValue(state)
}
}
const MyConnectedComponent = connect(mapStateToProps)(MyComponent);
I have a React component, AttributeSingleChoice which I am calling like this:
Based on the new props I receive in it, I want to change its state, like this:
componentWillReceiveProps: function() {
var attributeTypes = this.selectAttributes();
this.setState({
singleChoiceAttributes: attributeTypes});
},
selectAttributes: function() {
return this.props.classification.attributes.map(function (elem) {
if(elem.attributeType == "A") {
return {description: elem.description, name: elem.name}
}
}).filter(Boolean);
},
However, if I use componentWillReceiveProps, state.props will remember the old props, not the new ones, as I would like.
I tried using componentWillUpdate instead but I can't set the state inside componentWillUpdate.
How can I change the state of the component based upon new props?
The componentWillReceiveProps hook is passed the new props as an argument.
componentWillReceiveProps: function(newProps) {
newProps !== this.props
}
You can accept an alternate props with a parameter on your selectAttributes function.
selectAttributes: function(props) {
// fallback to regular props if nothing passed
props = props || this.props;
return props.classification.attributes.map(function (elem) {
// ...
}).filter(Boolean);
}
Then pass the new props when they are available.
componentWillReceiveProps: function(newProps) {
var attributeTypes = this.selectAttributes(newProps);
this.setState({
singleChoiceAttributes: attributeTypes
});
}
Your componentwillrecieveprops header is incorrect. You should take in a parameter for nextProps, which will contain the props being passed in. Then set your state variable based off of the nextProps. http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
You need to pass nextProps in to your function:
componentWillReceiveProps: function( nextProps ) {
var attributeTypes = this.selectAttributes( nextProps );
this.setState({
singleChoiceAttributes: attributeTypes});
},
selectAttributes: function( nextProps ) {
var props = nextProps || this.props;
return props.classification.attributes.map(function (elem) {
if(elem.attributeType == "A") {
return {description: elem.description, name: elem.name}
}
}).filter(Boolean);
},