Unmount React Parent without Unmounting Child - javascript

Is it possible for a React component's parent to be unmounted without the child being unmounted? What work arounds exist to achieve this result? Surely there must be some (potentially hacky) way to do this.
Example
When this:
<Parent>
<Child/>
</Parent>
changes to this:
<Child/>
I would like Parent's lifecycle method componentWillUnmount to be called without Child's lifecycle method componentWillUnmount being called.
I recognize this may not be possible but was wondering if anyone had a creative solution to this problem.
Update
Here's my specific use case (hopefully I do a good enough job explaining this):
I have a higher order component which doesn't introduce any new dom elements but essentially just introduces some new context for the child component. The child component renders slightly differently depending on whether or not this context is present. Unfortunately when I remove and add the parent a new instance of the child is created and it unmounts/remounts. The only issue with this unmounting and remounting is that the child element does some dom measurements to decide whether or not to show a horizontal scroll bar and overflow menu for some of it's elements. When it unmounts/remounts there is an unsightly flash of this menu.

You could handle the rendering logic. For example inside your render function:
if (showParent) {
return (
<Parent>
<Child/>
</Parent>);
} else{
return <Child/>;
}
Then whenever the boolean showParent changes the component renders differently.
The super-parent object, calling this render() , should store the state in order to update them and preserve the child (and parent, in case you want to switch it back on).
Therefore it should also contain the state of the child, in order for it to be kept. In other words: move the model hierarchically up to the super parent.

Related

Vue--How can the child component use some of parent component's data directly?

I'm learning Vue.js. Here I want to design a checkbox component like this:
<xxx-checkbox-group>
<xxx-checkbox></xx-checkbox>
<xxx-checkbox></xx-checkbox>
</xxx-checkbox-group>
Above are two kinds, the parent checkbox-group and the child checkbox. The checkbox-group use <slot> to get the children component and have some necessary data. I want the child can use some parent's data(just use not change). It's a bit troublesome and inefficient if I put a attribute in every child's tag.
<xxx-checkbox-group>
<xxx-checkbox shape="square"></xx-checkbox>
<xxx-checkbox shape="square"></xx-checkbox>
</xxx-checkbox-group>
Can I pass the value by other ways? So that I can controll all the children's state through the parent. I think it's possible but I can't find the way to achieve that.
<xxx-checkbox-group shape="square">
<xxx-checkbox></xx-checkbox>
<xxx-checkbox></xx-checkbox>
</xxx-checkbox-group>
For me it's not fully clear what's your intention, so can you create a small jsfiddle example?
but in general, within a child component you can access to it's parent vue instance via this.$parent to read & change properties.

What is the preferred way to show/hide components in React.js?

What is the preferred way to toggle (show/hide) a component in React? To my knowledge, there are two ways to do this.
Solution 1:
Conditionally rendering the child component inside the render() method of the parent component.
{
this.state.showUserModal ?
<UsereModal onClose={this.onModalClose} user={this.state.selectedUser}/>
: null
}
Solution 2:
Using a property at the child component which inside its own render() method returns null or the children based on the boolean.
<UsereModal show={this.state.showUserModal} onClose={this.onModalClose} user={this.state.selectedUser}/>
The second solution causes to initialize the component only once (the constructor is called once) and the first solutions do not. I am having issues with this because in need to initialize my state based on the props inside the constructor, so I am forced to use solution 2. But what are the most React way to handle this?
In both cases if the parent state or props are changed both the parent and the child components will be re-rendered. Hence there is no performance gain of the second solution. But if the child component should not be shown in the second case it will be mounted and rendered (but not shown). Taking it into account I would suggest to use the first case.
If you want to persist the DOM elements in the UI, you should go using style binding or class binding:
<UsereModal style={{display: this.state.showUserModal ? 'block' : 'none'}} />
I think the first solution is better since you do not need to initiate UsereModal component with its own state that will control should component be shown or not. I prefer also jsx notation for conditional rendering
{
this.state.showUserModal && <UsereModal onClose={this.onModalClose} user=
{this.state.selectedUser}/>
}

React ref a nested component

I ran into an issue which I do not know how to "properly" solve.
I have two components, let's call them parent and child.
child component is "generated" by a call to a function that creates it, let's call this function child creator.
parent component has a button which shows/hides the child but is also suppose to .focus() the HTML dom node which is what the child is. Now the show/hide I implemented via the state, but I do not know how to apply javascript's .focus() onto the child's HTML dom node.
There is also a small catch... the child component is being "generated" and "returned" by a call to a plain old javascript function, let's call it createChild.
This is due to the fact that child component needs to be vastly different based on what the parameters that were passed are, however, it also needs to be reused throughout the application so the createChild functions make sure that all the child components are the same, given the same inputs.
I tried passing ref to the creator, however since ref is not a prop, it is not accessible. What is the proper way to "grab" the children's dom nodes in order to .focus() them when the button is clicked since I cannot pass a ref?
Code sandbox link: https://codesandbox.io/s/lyj6x2948m
Yes, child ref is accessible since it is part of real DOM. I made a simple example with two nested components, check it out:
class Parent extends React.Component {
focusRef(ref) {
ref.focus();
}
render() {
return <Child focusRef={this.focusRef} />
}
};
class Child extends React.Component {
render() {
return (
<button
ref={childRef => this.childRef = childRef}
onMouseEnter={() => this.props.focusRef(this.childRef)}
>
When mouse enters, i get focused
</button>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById("root")
);
*:focus {
outline: 2px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root" />
Also, I strongly recommend further reading on react docs:
Okay for everyone wondering, I found a solution to the problem.
To begin with, the issue was not in the ref passing (at least not explicitly), but rather in a way controls are being created (which doesnt allow the ref to be passed).
The controlCreator function is a good old simple javascript function, and it was being used to provide a type for a React.createElement because the result of calling the controlCreator ends up being a react component.
I have however came to an understanding of why this is wrong and have instead proceeded to generate my child elements by the controlCreator and then using React.cloneElement to inject them with a ref. This way, the element is being cloned within a parent and can thus be referenced by parent's methods.
A link to a working code sandbox

How to bubble up an event to the very top parent React style?

I have a set of components app->page->list_container->list->item
My goal is to notify the app that click happened on item level.
If there is simple relation like parent->child I could use props and do something like: <Child onClick={this._onClick}> ... and then use this.props.onClick() to make a callback.
But what is the best native React-style receipt for doing the same trick with a tree of components? How to notify the app, that item was clicked without calling to Flux/Reflux, Elm and other supported libs?
Standard react way:
Passing onClick function as a prop down your component tree is the standard react-way of doing this.
In <app>:
<page onClick={this._onClick}>
In <page>:
<list_container onClick={this.props.onClick}>
Etcetera.
Or you could use:
<list_container {...this.props}>
To automatically pass down any prop from parent component to the child component.
In a deep tree, this can and will get quite tedious/ lot of work. React was not designed for this purpose.
React is made for (top-down) smart and fast component-tree rendering.
The frameworks for the flux pattern you mention are designed to handle the other interactive functions.
Alternative shortcut (not recommended):
A shortcut you could possibly use is to add a listener directly on the DOM, inside your <app> component, that handles the click event on the item:
In <app> component, add:
componentDidMount: function() {
var itemElementInDOM = document.getElementById('myItem');
itemElementInDOM.addEventListener('click',this._onClick);
}
And in your <item> component, give the item a (unique) id.
I would generally NOT recommend this:
In a typical react tree setup, the lower level components (like
<item>) may be rendered more than once, and then you would need
additional logic to ensure that each ID is unique.
You would also
need to add some additional smarts to make sure you remove the listener if the
item(s) in question are removed from the DOM.

React component not displaying if dynamically generated list items empty

I have a react component that contains a child list of components created using a map:
var listItems = model.arrayItems.map(function(item) {
return(<ChildComponent item={item}></ChildComponent>)
}, this);
And the component's render function then adds this list of child components:
return (
<div>
<h1>My items:<h1>
<ul>{listItems}</ul>
</div>
);
The problem is that the react component is not showing up in my browser when listItems is empty. However, if I resize the browser window, the component does show up. Does anyone have any advice on what might be causing this behavior?
So it did turn out to be an issue with ChildComponent. In fact, it seems to have been a CSS issue.
ChildComponent itself had a nested set of dynamically generated list items. These grandchild components had the CSS property for width set to 100%. Changing this property to "auto" fixed the issue.
My understanding is that when transitioning to a state in which the top-level list is empty, and given the way React is managing unmounted components, the grandchild component's CSS style of 100% (of parent element) somehow confuses the browser's rendering because its parent component is no longer mounted. If anyone knows the cause of this behavior in more depth, it would be great to hear a deeper explanation of this.

Categories

Resources