Hello i have a problem whenever i reload my page i want to call a beforeMount() method to call my filterRecords (computed method) so that i can receive the data ,but it is just not working fine it is telling me that filterRecords is not a function.
My computed:
computed: {
...mapGetters({
sec: "sec"
}),
createdDate() {
return moment().format("DD-MM-YYYY ");
},
createdHours() {
return moment().format("HH:mm ");
},
filteredRecords() {
return this.records.filter(record => {
return record.template_id === this.sec;
});
}
},
so i just do this:
beforeMount() {
this.filteredRecords();
},
it is not calling it so i get nothing to my filteredRecords.
how am i able to call it when i reload the page ( i am recieving the records data from an API rails)
Be sure to check the Vue docs about computed properties.
You should not call them as functions, but as properties (since they are computed properties).
You can try to console log filteredRecords in the beforeMount hook like this:
beforeMount() {
console.log(this.filteredRecords)
},
This seems like a fundamental misunderstanding on how Computed properties work. Computed properties are accessed the same way you would access props or data on a component. They are consumed as values, not as methods. A big hint to this fact is that you're calling map**Getters**
You could consume filteredRecords in your template something like:
<div v-for="record of filteredRecords" :key="record.someKey">...</div>
or by assigning it to a data property
this.records = this.filteredRecords
Related
Trying to solve page refresh issue that occurs using vuex and getters. I must be missing something on how the reactivity works, but haven't been able to identify what after searching around and reading vue pages on reactivity.
As an example, I have a component that will initially load just fine:
Create lifecycle dispatches action to retrieve data from API and push to array in state
Computed property in component retrieves data using getter (filter array to specific person)
Component displays a few properties in array
When page is refreshed it seems that the action is called again and data retrieved but it doesn't seem like the getter works correctly to get the new data and page does not load. If I test accessing the data in the state directly then refresh works fine. So it seems that the data is properly loaded to the state when refreshing but the getter somehow doesn't have it?
Appreciate any help!
Component:
<script>
export default {
props: ["id"],
computed: {
player() {
return this.$store.getters["player/getPlayerById"](this.id);
}
},
created() {
this.$store.dispatch("player/fetchPlayer", this.id);
}
};
</script>
getter:
getPlayerById: state => id => {
return state.players.find(plr => plr.PlayerID === id);
}
action:
var promise = EventService.getPlayer(id)
.then(response => {
commit("ADD_PLAYER", response.data);
})
ADD_PLAYER mutation:
ADD_PLAYER(state, player) {
state.players.push(player[0]);
}
I'm using the created lifecycle hook in vue.js to load data from my store to the data for a vue component. I noticed that this.selectedType = store.state.selectedType successfully loads the data from the store. However, if I use the getter to load from the store (i.e. this.selectedType = store.getters.getType()), I get the following error:
Error in created hook: "TypeError: Cannot read property 'selectedType' of undefined"
I don't understand why it is saying that selectedType is undefined because selectedType has the value "Item" in the store and is correctly loaded on create if I use this.selectedType = store.state.selectedType.
The getter is defined as such:
getters: {
getSelectedType: state => {
return state.selectedType
}
}
And the state is defined as:
state: {
selectedType: "Item"
}
Could someone please explain why this occurs? I'm hunch is that there is something about the lifecycles that I don't fully understand that is leading to this confusion.
You are not supposed to call getters. Just like computed properties, you instead write it like you are reading a variable. In the background the function you defined in the Vuex store is called with the state, getters (and possibly rootState and rootGetters) and returns some value.
Beside that, it is usually an anti-pattern to use a lifecycle hook to initialise any variable. Local 'component' variables can be initialised in the data property of the component, while things like the vuex state usually end up in a computed property.
The last thing I want to point out is that, if you have correctly added the store to your Vue application, you can access the store in any component with this.$store. To use getters in your application, you can use the mapGetters helper to map getters to component properties. I would recommend using something like this:
import { mapGetters } from 'vuex';
export default {
// Omitted some things here
computed: {
...mapGetters({
selectedType: 'getSelectedType'
})
},
methods: {
doSomething () {
console.log(this.selectedType);
}
}
}
Which is functionally equivalent to:
computed: {
selectedType () {
return this.$store.getters.getSelectedType;
}
}
I am currently stuck at trying to show a form to edit a existing site.
My Problem is one site has about 60 Input fields and writing setters and getters for every input seems not like a good approach.
So the best thing I could think of is to save my store data to a local variable, edit the local variable and send it back.
Edit.vue
<b-form-input id="currentSiteName" v-model="this.editSite.title"></b-form-input>
...
computed: {
editSite() {
return this.$store.state.currentSite
}
},
mounted: function() {
this.$store.dispatch('SHOW_SITE', {
siteId: this.$route.params.id
});
},
Store action
SHOW_SITE: function ({ commit }, siteParams) {
http.get('/sites/' + siteParams.siteId).then((response) => {
commit('SHOW_SITE', {
site: response.data.foundSite
});
},
(err) => {
// eslint-disable-next-line
console.log(err);
})
},
Store mutations
SHOW_SITE: (state, { site }) => {
state.currentSite = site;
},
If I look in my vue-dev-tools I can see that editSite has the correct values and the values are all shown in the form but i get following two errors:
Error in event handler for "input": "TypeError: Cannot read property 'editSite' of null"
Cannot read property 'editSite' of null at callback
What I am doing wrong here or is there a better / c way to solve my problem?
Any help would be greatly appreciated!
You should use getters for access to store states.
import { mapGetters, mapActions } from 'vuex'
async mounted() {
await this.showSite(this.$route.params.id);
},
computed: {
...mapGetters([
'currentSite',
]),
},
methods: {
...mapActions([
'showSite'
]),
},
Now, this way you should able to access store states without null exception. And you should use async await for http.get. This way your code looks cleaner.
The following documentation provides a helpful explanation of what I think you are trying to achieve: https://vuex.vuejs.org/guide/forms.html
In short, bind the :value attribute of the form field to the computed property. Listen to a change event and ensure that the actual mutation of the Vuex store property happens within a Vuex mutation handler. Also, note the use of the MapState function which acts as a nice little helper to map store properties to component computed properties.
Make sure that you are thinking of the Store state prior to when the AJAX request has completed and updates the store. Setting a default state for the store will help alleviate any null references. Also worth noting that this. in the "this.editSite.title" attribute binding is unnecessary.
I have a function getBar() returning an object like:
{
foo: 'value',
array: ['a', 'b', 'c']
}
Here's my React component calling the above function i.e. getBar():
class foo extends Component {
state = {
bar: {}
};
componentDidMount(){
this.setState({
bar : getBar()
});
}
render() {
{this.state.bar.array.map((value, i) => <div class="row" key={i}>{value}</div>)}
}
}
It always gives me Uncaught TypeError: Cannot read property 'map' of undefined error. Exploring similar questions, I came to know I will have to declare an empty state array which I did in different ways but none worked. Can anybody please give me an appropriate answer preferably with complete logic.
I tried another way of declaring the state array to a const in render() but didn't get successful results.
Ok, so this is actually something to do with your component's lifecycle
The problem is that your render method runs before the componentDidMount method. So the first time your component renders your state looks like this:
{
bar: {},
}
So no array property on bar, which means you cannot map over it (which is why you get errors 😣). Instead you could use the componentWillMount method, to set the state before the render method runs, or you could do a check on array being set before mapping over it.
I have a React class, and it wants to render an object shown below:
data: {
title: "haha",
description: {
country: "US",
year: "1996"
}
}
But, when React wants to render it, it gives an error.
Uncaught Error: Invariant Violation: receiveComponent(...): Can only update a mounted component
I think the problem is in the getInititalState, I declare my data as an empty object, so when I get my full data object after the timeout, React will try to map my data object to the component, but it gives error.
But one interesting thing is, I have no problem accesing this.props.title.title, but not this.props.title.description.country, it will give undefined
But, when I console.log it, I could see my object. But React cant access it!
My guessing is when React initializing from the empty object, it will only init the virtual DOM with the 1st and 2nd level of the data object.
That the reason, when I try to access this.props.data.data.title is OK but not this.props.data.data.description.country
Below is my code
var BookBox = React.createClass({
getInitialState: function() {
return { data: {} };
},
componentWillMount: function() {
var that = this;
setTimeout(function() {
console.log('timeout');
that.setState({
data: {
title: "haha",
description: {
country: "US",
year: "1996"
}
}
});
}, 2000);
},
render: function() {
return (
<div>
<h1>{this.state.data.title}</h1>
<TestBox title={this.state.data} />
</div>
);
}
});
var TestBox = React.createClass({
render: function() {
console.log(this.props.title);
return (
<div>
<p>{ this.props.title.description.country }</p>
<p>{ this.props.title.title }</p>
</div>
);
}
})
May I know what is the best way to handle this problem? should i init my data object structure in the getInitialState or there is a better way?
I think you are getting Can only update a mounted component error because you are using componentWillMount and settimeout together, but you dont know if the component has been mounted by the time settimeout function fires.
Since you know what your state is beforehand, I think it is best to return your data from getInitialState function.
You can also use componentDidMount instead of componentWillMount function. That way you can be sure the component is mounted when componentDidMount is called.
Any time time you are using asycn functions like settimeout or a xhr call, you should use this.isMounted() in the callback function, to check that the component is still mounted by the time the callback fires.
For example, if you didnt know the state beforehand, you could fire an xhr call in the componentDidMount function, check this.isMounted() in the success callback and setState.
As for the error on <p>{ this.props.title.description.country }</p> line: At initial render this.state.data (BookBox) is an empty object so is this.props.title(TestBox). Accessing empty object's ({ }) title property is undefined. No problem there. Accessing description is also undefined. But accessing undefined's country is error. To avoid this error you can create a description variable: description = this.props.title.description || {} and use <p>{description.country}</p> to make sure your code doesnt break if this.props.title is empty.