My parent component is a list of tabs. Clicking on tab leads me to Child #1 or Child #2. I can also route to Child #1 or Child #2 by URL. In this case, I check the path to know which tab to select programatically.
My problem comes when I redirect from one child to another. My parent is oblivious to the fact that a change has occurred - none of the initializing functions in that component get called, since it is already rendered. Therefore the tab that was originally selected (Child #1) - remains selected even though I am now viewing Child #2.
The tab that is selected is being stored in the parent's state - is there any way for me to update the parent's state from the child component?
Pass a function down to the child(ren) from the parent that modifies the state accordingly. A very simple version could be something like:
class Parent {
setActive(activeId) {
this.setState({active: activeId});
}
render() {
return (
<Child setActive={this.setActive}/>
);
}
}
Related
I have to update state of the parent class component from child functional component only when a click event takes place in the parent component. Right now I've access of the data from child to parent component but when I update the state I get error, maximum depth reached. So I thought it'd be better to update the parent's state from child only when the certain event takes place in the parent component but I'm unable to find any approach. Could you please show some light?
From your description, the best thing to do is to lift state up from the child to the parent so that the information you currently only have in the child is available in the parent (which can provide it to the child as a prop). Then, the child isn't involved in this at all, the event in the parent updates the parent's state, which is standard.
But if you absolutely can't do that:
It's taking you off the beaten path, but you could:
Have the parent pass the child two things:
a means of subscribing to an event from the parent
a function to call to update the parent's state
Have the child subscribe to the event
Have the parent raise the event the child subscribes to when the click occurs
Have the child respond to that event by calling the function from (1)(2) above
While that would work, it's a bit convoluted. So again, if you can avoid it, move the state needed for the update from the child to the parent and keep the entire update in the parent.
Finally I figured out a way to achieve it.
Step 1: Set a boolean for your event taking place in your parent state using useState hook.
// Inside Parent component
const [eventInParent, setEventInParent] = React.useState(false);
Step 2: pass the eventInParent as prop to your child component
// Inside Child component
Step 3: Receive the event status (eventInParent) in your child component in your props and use it as a dependency in useEffect hook
React.useEffect(() => {
if(eventInParent) {
}
}, [eventInParent]);
As you can see every time event will hit in parent component the eventInParent value will change which will trigger the useEffect hook in the child component.
I have a VueJS project - which in one view there are parent and child components that are both using the same component called deleteModal.
When I trigger the modal from the child (to show it), it triggers both the child and parent modals (except no data is passed to the modal triggered by the parent). As I understand it, this is because I have used the component twice - in the parent and child - example below. To note, it works as expected from the paren
I've researched and tried a few things: setting a key value for each of the components, changing the components ref name among other things. I have also tried using v-show to only show component just before I trigger the parent model however, this solution is not ideal.
How can I only trigger the modal from the child?
Parent Component
<template>
<div>
<childCompt ref="childCompt" />
<deleteModal
ref="deleteModal"
#deleteTriggerAPI="deleteAPIParent"
/>
</div>
<template>
Child Component - childCompt
<template>
<div>
<deleteModal
ref="deleteModal"
#deleteTriggerAPI="deleteAPIChild"
/>
</div>
<template>
My old answear is not good at all. I personally to show and hide element using jquery in vue. For me right now this is best solution but maybe i don't know some best.
If you want use only vue i using also variable passing to child from parent which will support visable of your modal.
We pass variable with ":" and register event with "#".
<template>
<childComponent :isModalOpen="isModalOpen" #onModalClose="isModalOpen=false">
<template>
export default {
name:"parent",
data: () => {
isModalOpen: false
}
}
In child we catch this by using props. We need to define type of varialbe we pass. Different between props and data is that in props we cannot change value in child component.
export default {
name: "child",
props: {
isModalOpen: Boolean
}
}
And you can use this variable to show or hide modal. Also in child component we can create button to close modal and we emit event to parent in order to change variable value.
To do this we using this.$emit('eventName');
More information right here: https://forum.vuejs.org/t/passing-data-back-to-parent/1201
You could try globally defining the component,
ie, in main.js
Vue.component('deleteModal',deleteModal)
I have a callback function which receives an argument from child component(here CardTiles) and it is processed and passed as props to another child component. The output is displayed correctly but I have to move my page to that particular section(the second child component-OutputWindow). How can i trigger an anchor tag from my 1st child component? or would refs work here?
Child component 1:
<CardTiles parentCallback={handleCallback}/>
Child component 2:
<OutputWindow name={place}/>
or would refs work here
Yes. Have a ref in the parent, put it on the child (ref={theRef}), have the child forward that ref to the outermost (probably) HTML element it renders, and then in the callback function have the code use theRef.current?.scrollIntoView()¹ to scroll that element into view.
More
Refs
Forwarding refs
scrollIntoView
¹ That's using optional chaining, which is fairly new. If your project isn't set up for it, you can use if (theRef.current) { theRef.current.scrollIntoView(); } instead.
I'm looking to do this dynamically. I have a parent component which has two children components. Each children is nested inside its own div. Both children can update and, due to their content's nature, change height independently. I want to guarantee child component 1 div always has equal or greater height than child component 2. When it doesn't, I want it to dynamically change to match its sibling. The code:
class Parent extends Component {
render(){
return(
<div className="childComponent1wrapper">
<ChildComponent1/>
</div>
<div className="childComponent2wrapper">
<ChildComponent2/>
</div>
);
}
}
I thought about saving each children component's height in a store and passing the prop to parent component as a prop, but it seems overkill.
I've tried using parent's onComponentDidUpdate() but it doesn't trigger when children update.
How could I achieve this? Thanks
I built a simplistic tab container in ReactJS using the idea that the container component keeps in its state an integer index denoting the tab pane to display and then renders only the child (from the this.props.children array) that is found at that index position.
The gist of this approach was:
const TabContainer = React.createClass({
props: {
tabNames: React.PropTypes.arrayOf(React.PropTypes.string).isRequired
},
getInitialState: function() {
return {
activeIndex: 0
};
},
setTab: function(n) {
this.setState({activeIndex: n});
},
render: function render() {
const childToRender = this.props.children[this.state.activeIndex];
return (
<div className='tab-container'>
<Tabs
tabNames= {this.props.tabNames}
active = {this.state.active}
setTab = {this.setTab}
/>
<div className='tab-pane'>
{childToRender}
</div>
</div>
);
}
});
I.e. only the indexed child is selected and rendered (I've omitted for the sake of simplicity the code handling the edge case where this.props.children is not an Array).
I found out that this approach was unsatisfactory as when the user selected different tabs, the component corresponding to the pane to render was mounted and unmounted repeatedly and any state that the panes had could not be preserved.
Ultimately, I used an approach in which all children are rendered and all panes, except the selected one, are assigned a class hidden that is then used to style those panes as: display:none. When this later solution was used my panes remained mounted even after the user clicked through the various tabs and any state they had wasn't lost as the user cycled through the tabs.
My questions are:
was the initial approach (where only a specific child is rendered) an anti-pattern or was there some other mechanism I could have used to preserve the state of the individual panes or prevent them from being unmounted?
if the initial approach was indeed an anti-pattern how can that anti-pattern be expressed more generally?
I don't think the initial approach was an antipattern at all. Choosing whether or not to mount/unmount in your logic is just dependent on your circumstances. If you want state preserved, then don't unmount. If you want a fresh element, complete with a call to getInitialState, then unmounting is the right way to go.
As an easy counterexample, consider React-Router. The Router completely unmounts/remounts components on route change. And route changing is effectively just a higher order of tabbing.
But given the situation where you want state preserved, I think your solution is the proper one. You might want to take a look at material-ui, which does something very similar in their tabbing: https://github.com/callemall/material-ui/blob/master/src/Tabs/TabTemplate.js