Ok so let's say I have 2 components in vue, Parent.vue and Child.vue.
In Child.vue I have this
data () {
return {
childData
}
},
In Parent.vue I get the data from child using this
data(){
return{
dataFromChild : child.data().childData,
}
},
Everything good here but I have one problem, childData will get updated based on what the user does, how do I make so that dataFromChild updates whenever childData updates? I would prefer not to use event bus or vuex as it is overkill for my case.
JavaScript (and thus Vue.js) is event-driven. Are you sure using events are overkill for your case?
In an essence, you want to update the parent data, when the child data change. This change is an event. "Something" is happening, so your Parent can react to it.
I assume that you are setting the ref on the child component. I'd like to bring your attention to this section of the guide:
$refs are only populated after the component has been rendered, and they are not reactive.
I recommend you to use Vue.js event system:
https://v2.vuejs.org/v2/guide/components-custom-events.html
Related
I've starting exercising vuejs and I've learned that to communicate data from child component back to parent component we use this.$root.$emit('name-of-event', myobject);
which would be received from parent with the help of this.$root.$on('name-of-event');
In the other hand, I got a vuejs project which I use to compare what I had learned with what is implemented in it and there I found that the component listening to my event is not the parent of that component (the tag of the component triggering the event is not rendered in the one who is listening to it)
My question: is it always the case that the direct parent is the one who listens to the triggered event ? could other component be listening to emitted events ?
myAcomponent.vue :
updateDate(value) {
//body of updateDate method
this.$root.$emit('date-updated', this.project);
}
myBcomponent.vue :
<script>
created() {
this.$root.$on('date-updated', project => {
this.updateproject(project);
});
}
</script>
<template>
//no call in template for myAcomponent
</template>
Is it always the case that the direct parent is the one who listens to the triggered event ? - Answer is Partially Yes, There are two scenarios or use cases :
If you are working on a large application and there is a need to share data between multiple components and these components don't have any relation with each other, then you have to use a state management solution. You can use Pinia - which is the state management library recommended by the Vue core team.
If you want to share the data only between the siblings under single parent, In that case you can give a try to this solution.
Pass data from one child to parent component using event emitter.
Capture the event in parent and then pass back to another child by using props.
there is a better way to improve the event emit
lets say you have component A and B you want to transfer data from A to B also they don't have direct relationship
1.create JavaScript file and add the below code on JavaScript file save it FIleName.js
import Vue from 'vue';
export const EventBus = new Vue();
2 on component A.vue emit the event on methods or on api call
import {EventBus} from "path/FIleName.js";
update(data){
EventBus.$emit("event-name",Data);
}
3 the last thing you want to do is listen on a component B.vue which you want to get the data or the event and fire a function to do something with the data you passed
import {EventBus} from "#/service/EventBus.js";
created() {
EventBus.$on("gallery-created",(Data) =>{
this.MyFunction(Data);
})
},
By doing this you can pass an event and data to any component using event bus method.
I'm making a map interface to manage the map-related data. like link, nodes, vertex, and so on.
I'm facing the issue that I'm not sure how to detect changes in a grand-child component when data changes from grandparent component. Please advise me.
component tree:
grand parent: map container + tables to display map data(import map(child))
parent: map + leaflet-draw customized component (import edit-map(child))
(grand)child: leaflet-draw customized component
Using Vuex to share data
grandparent: get data(vuex), display, catch the updated data(completed) - ok, no problem
grand-child: add, edit, delete data. updated data will be sent to vuex. - ok, no problem
issue: Users can modify data also by using a table in grandparent.
problem: not sure how to detect changed data from grand-child component.
I can see the object values are changes automatically when I change data in the table... but I really have zero ideas on how to detect that changes in grand-child component...
let me know if you need more info.
Edited:
I've converted leaflet-draw vanilla js to grand-child component. All my codes are written in < .s .cript> </> above export default { data(), methods: {}, compueted:{} }. Only mounted() hook is used to display the component to parent(map) component. This is why I have no idea how to detect changes....
In VueJS, I have seen different ways of accessing parent properties from a component. Say I want to use the parent property items in my component.
First way
The component has a props value bound to a parent property:
.js
Vue.component("example", {
template: "<div></div>",
props: ["myItems"]
});
.html
<example v-bind:my-items="items"></example>
Second Way
The child component accesses a parent's properties directly, like this:
this.$parent.items
Question
Is there a reason to use the more elaborate first method over the second? Is there an overhead to "duplicating" data like that, vs. accessing it directly when needed?
The props should be mutated in the parent component, according to the official doc :
All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to understand.
In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console
So in order to update props from child component you should use this.$emit event and send the new value in order to handle the update in the parent one.
I have a component ProductList - it's a parent component. In m render method i wrote such code
return (
<div>
<CustomBreadCrumbs routes={this.props.routes} params={this.props.params} />
{ this.props.children ? this.props.children :
<section className="content">
Parent
</section>
}
</div>
);
When I edit some info in child component my parent component rerender, but i want prevent it. How i can do it?
This is impossible, because only on rerendering parent component calling rerendering of the child.
As you can see there, if you will prevent rerendring of current element with shouldComponentUpdate, the childs render methods will not hired.
But dont worry React Only Updates What's Necessary. So, if your html of the parent element will not change, the real DOM will update only child`s html.
Show case
There is an example in official documentation, of how to create forms. In a few words, your main problem, is that you dont save your values anywhere, as I see, you use Redux and passing all of the data via props. Try to change your code, to save the data in the own state of the component.
And if you will catch an error on BadRequest, you will fire the code, check the equality, for example for message (of an error) and update your component, but your current state, with all user`s data will not be changed.
shouldComponentUpdate(nextProps, nextState) {
//there you will get the new values and check it, if they not equal
}
componentDidUpdate(prevProps, prevState) {
//there you can do anything with your new values
}
And if you r using Redux, take a look to Redux Form.
All props form a one-way-down binding between the child property and
the parent one: when the parent property updates, it will flow down to
the child, but not the other way around. This prevents child
components from accidentally mutating the parent’s state, which can
make your app’s data flow harder to reason about. In addition, every
time the parent component is updated, all props in the child component
will be refreshed with the latest value. - One-Way Data Flow
The Vue2 Component Docs suggests doing the following to use props as an initial value:
// via https://v2.vuejs.org/v2/guide/components.html#One-Way-Data-Flow
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
So in my code I mimicked those instructions here.
However data() in Note.vue isn't being updated even though the prop value is received according to vue-devtools.
Haven't had success setting the values with the mounted or created lifescyle methods.
When I use static data, this seems to work fine, how can I ensure the child component reacts to receiving props when it comes from a remote source?
When you are passing initialNote as prop for initial value, but I see initialNote is being populated asynchronously in getNote method, so it will not be present initially when the component will be mounted. It will be populated after some time by the time initialisation would have already happened.
In the example give in vue documentation, initialCounter is static value which will perfect as it will have same value from beginning.