I am making a form built of Vue JS components. I have the following components tree (each component contains the child below it ex. User Registration Form has the Form component as its direct child).
User Registration Vue Component
Form Vue Component
Input Vue Component
Input Option Component
After all of the components have full rendered I need to run a function in the User Registration. I tried putting it in the mounted function in the User Registration Vue Component but it runs before the Option Components have completed their mounted function.
I read here: https://medium.com/#brockreece/vue-parent-and-child-lifecycle-hooks-5d6236bd561f that this should not happen and that the child component should be completely mounted before the running the parent mounted function, in this situation the User Registration Vue Component.
I have about 100 components total including the Form, Inputs and all of the options.
I can only run this desired code in the User Registration Vue Component after everything has fully rendered and loaded. I tried using the jQuery(document).ready function but I have inconsistent results (sometimes the document is ready before the forms have fully mounted).
Any recommendations?
If you need to know when a component has been created, mounted, updated etc. from a parent component, you can just define a listener using #hook: followed by the lifecycle hook name.
E.g. from the parent component to execute doSomething() once the child component is mounted:
<child-component #hook:mounted="doSomething" />
Since the child mounting could be delayed more that nextTick(), you can emit an event programatically:
Child JS:
{
mounted: function() {
this.$emit("mounted");
}
}
Parent HTML:
<child #mounted="childMounted">
Parent JS:
{
methods: {
childMounted: function() {
// TODO child action
}
}
}
An alternative is to use the child component as a mixin
Define a directive:
Vue.directive("mounted", {
inserted: function(el, binding) {
binding.value();
}
});
You don't need to modify the child, only the parent:
Parent HTML:
<child v-mounted="childMounted">
Parent JS same as in (2)
mounted() hook of the parent component does not guarantee that all child component also finish rendering.
To execute something once the whole view has been rendered use vm.nextTick() inside the the parent component's mounted() hook.
//User Registration Vue Component
mounted(){
this.$nextTick(()=>{
//execute your code
console.log('Finished rendering the complete view')
})
}
Refer to - mounted lifecycle hook
Thanks #Tires, it works well
Vue.directive("mounted", {
inserted: function(el, binding) {
binding.value();
}
});
Parent:
<child v-mounted="childMounted">
{
methods: {
childMounted: function() {
// TODO child action
}
}
}
Related
I have prop in child component -> kpi_kalite[]
Parent component-> mounted():
*(This kpi_kalite is created in parent component's data)
axios.get(URL+ "/KPI/").then(response=>{
console.log(JSON.parse(JSON.stringify(response.data)))
this.kpi_kalite.push(response.data[0])
})
I do 'get request' in parent componenet and i push the response.data to kpi_kalite[] (parent component)
And i use this array for props.
Then, I want to do console.log(this.kpi_kalite) in beforeMount or Mounted.
But this props in not using.
methods : {
set_input(){
console.log(this.kpi_kalite)
for(const i in this.kpi_kalite){
console.log(i)
console.log(JSON.parse(JSON.stringify(this.kpi_kalite))) // output
// "undefined"
}
}
},
beforeMount() {
this.set_input()
}
console output : undefined
Could you help me? ,Before HTML-css loaded, I need parent component's data in child component
There is a post by LinusBorg about the order of lifecycle hooks for parent and child:
There’s nothing weird or wrong about it, it all follows from the
lifecylce logically.
beforeCreate() and created() of the parent run first.
Then the parent’s template is being rendered, which means the child components get created
so now the children’s beforeCreate() and created() hooks execute respecitvely.
these child components mount to DOM elements, which calls their beforeMount() and mounted() hooks
and only then, after the parent’s template has finished, can the parent be mounted to the DOM, so finally the parent’s beforeMount()
and mounted() hooks are called.
END
Also, there is a nice diagram here.
Child components are mounted before the parent component is mounted. Therefore, console.log(this.kpi_kalite) in the child component does not print the data gotten from the axios in the parent. So, if you do not render the child component at first, it will not be mounted because it is not created. If you render the child component after the axios is completed, it will be created and mounted. Then, console.log will print the value of kpi_kalite gotten from the axios in the parent.
ParentComponent:
<ChildComponent v-if="renderChildComponent" :kpi_kalite="kpi_kalite" />
data() {
return {
kpi_kalite: [],
renderChildComponent: false,
};
},
mounted() {
axios.get(URL+ "/KPI/").then(response=>{
console.log(JSON.parse(JSON.stringify(response.data)))
this.kpi_kalite.push(response.data[0])
this.renderChildComponent = true;
})
},
I have a parent and a child component. I want to pass data from child to parent.
If a function is called within the child component, is there a way to update and pass data in the child component to the parent component?
Looking online, most examples involve clicking a button in the child component then sending to the parent. But in my case, there is no clicking a button event, only if a function is called.
How would we do this? Thank you
It sounds like you were trying to avoid events only because you assumed the event had to come from a button click, but that's not true. The event could be a function called after a timeout, for example. For direct child to parent data communication, events are commonly used to pass data up from the child.
vm.$emit() can be used in the child to pass data to the parent:
// Child.vue
export default {
mounted() {
// aritifical delay
setTimeout(() => this.emitDataToParent({ foo: true }), 1000)
},
methods: {
emitDataToParent(data) {
this.$emit('my-event', data)
}
}
}
The parent component can add an event handler with v-on:EVENT_NAME (or use #EVENT_NAME for shorthand) to receive the child's data:
<template>
<Child #my-event="handleMyEvent" />
</template>
<script>
export default {
methods: {
handleMyEvent(data) {
console.log(data)
}
}
}
</script>
demo
I need to display a spinner in vue for every component (this is the requirement).
For that I think about to do v-if="loading" inside component HTML.
My question is how to detect when component is loading complete? (meaning after the DOM is rendered, and the data-bind is resolved to the DOM elements)
According to Vue lifecycle when update function is trigger then the render is complete.
So for that I'll need to implement for every component update function that change the loading to false. is there eazy way to do that? for example one place to write the update function? can I do that without implement extends? any sophisticated way to do that?
What I need for example is this.loading available in Vue instance.
Of course you can do it. Vue mixins come in rescue.
Mixins are a flexible way to distribute reusable functionalities for
Vue components. A mixin object can contain any component options. When
a component uses a mixin, all options in the mixin will be “mixed”
into the component’s own options.
Notice that you should use mounted hook if you want to track when the component is inserted into DOM.
Called after the instance has been mounted, where el is replaced by
the newly created vm.$el. If the root instance is mounted to an
in-document element, vm.$el will also be in-document when mounted is
called.
mixin.js:
export default {
data() {
return {
loading: true
}
},
mounted() {
console.log('I have been mounted')
this.loading = false
}
}
And then register that mixin globally, so it will be available in all components:
import mixin from './mixin'
Vue.mixin(mixin)
how to force render our component when props changes?
how to force render parent component when child component's props changes?
i searched a lot but all solutions are deprecated in new React version.
in my any pages (Route exact path="/post/:id" component={post}) for example (siteUrl/post/1) i am getting (:id) from props (this.props.match.params) and that works.
but when i am in single page component (Post) and this Route (siteUrl/post/1) when i am passing new Props to this component (:id).
props will changes but single component and parent component Will not re render...
You may be using componentDidMount method.
componentDidMount() is invoked immediately after a component is
mounted (inserted into the tree). Initialization that requires DOM
nodes should go here. If you need to load data from a remote endpoint,
this is a good place to instantiate the network request.
but you need to use componentDidUpdate.
componentDidUpdate() is invoked immediately after updating occurs.
This method is not called for the initial render.
You can also use state and other React features without writing a class.
read more: https://reactjs.org/docs/hooks-effect.html
To make both parent and child re-render you need to path prop from parent to it's child.
// parent using
<Parent someProp={{someVal}} />
// parent render:
render() {
const { someProp } = this.props
<Child someProp={{someProp}} />
}
this will surely re-render both components, unless you stated another logic in componentShouldUpdate
in your case Router looks like a parent for Parent so you should only path :id as a prop.
Make sure Router is at the top level, right under the App
Important is ,that you initialise the someVal of the child first in the constructor
public static getDerivedStateFromProps(
nextProps,
nextState
) {
let { someVal } = nextProps;
if (nextState.someVal !== someVal) {
return {
initialVal,
someVal: someVal
};
}
return null;
}
After it will rerender on prop changes because the state changes
Right now I have a sidebar that I want to use for various forms and bits of information. I'm using the global event system to trigger the opening of the sidebar, but I'm not sure how to inject react components into the sidebar react component.
I started by trying this
componentWillMount: ->
window.toggleSidebar = (react_component)=>
React.renderComponent(react_component(), document.getElementById('sidebar-content'))
#toggleSidebar()
But this didn't work once all of the components are mounted because you can't call render component into an element that is inside another component.
So is there an accepted way to pass any react component into another component?
You don't actually want to pass a component instance, you want to pass the component factory and data that it can use to render the component.
events.emit('sidebar-change-request', {component: Foo, props: obj, open: true});
And in the sidebar component it'd be listening to the event:
getInitialState: -> component: React.DOM.div, props: {}, open: false
# standard event emitter stuff
componentDidMount: ->
events.addListener 'sidebar-change-request', this.handleSidebarChangeRequest
componentWillUnmount: ->
events.removeListener 'sidebar-change-request', this.handleSidebarChangeRequest
# simply apply the payload to state
handleSidebarChangeRequest: (payload) ->
this.setState payload
# dynamically render stuff
render: ->
if this.state.open
React.DOM.div {className: "sidebar"},
this.state.component this.state.props
else
React.DOM.div null
If you needed to get some information back from the component renered in the sidebar, you'd pass a callback to that components via props; or the component could emit events.