Unmounting a React component the correct way - reactjs

export class Child extends React.Component{
unmount() {
const node = ReactDOM.getDOMNode(this);
ReactDOM.unmountComponentAtNode(node );
}
render() {
return <button onClick={this.unmount.bind(this)}>Unmount</button>
}
}
For the above sample component, would it possible to unmount it on click using unmountComponentAtNode?

React application is always a components composition, or in different words - components tree. It means that every component has parent component, which renders it, it is only falsy statement for root component, mostly we name it App, but we do not talk about it in that question. Above all, we can say that a component, which needs to be unmounted, always has a parent component.
As we did the assumption in first paragraph, the correct way of unmounting React component is to remove it from render method in parent component. It can be done in many ways, the simplest is just an conditional component rendering like:
class IAmParentComponent extends React.Component {
render() {
return (<div>{this.state.show && <YourChildComponentToUnmount/>}</div>)
}
}
Above example shows IAmParentComponent as container component which holds a state, and the YourChildComponentToUnmount will render if this.state.show is true, will unomount after state change from true to false.
Back to your code with callback, the callback should be send into component by props, and the parent component should do the state change related to removing the component from render tree, what exactly will start unmount phase of the component, and finally component will be removed from UI.
In conclusion, component unmount should be in responsibility of component above it, component should not unmount itself.

This is not the way react.
The best way to unmount an element is to tell the parent to remove the child from the rendered children of the parent.
Look at this example.
Here we have the CardContainer class and CardItem class.The CardItem item class has a delete self button. This method send an event to the parent container to remove itself from the rendered children.
const carddata = [
{key:1 ,name: 'Card A',visible:true},
{key:2 ,name: 'Card B',visible:true}
];
class CardItem extends React.Component {
constructor(props){
super(props)
this.handleClick=this.handleClick.bind(this);
}
componentWillUnmount(){
console.log('unmount')
}
handleClick(){
this.props.destroy(this.props.id)
}
render(){
return(<div>
Card
<button onClick={this.handleClick} >delete</button>
</div>)
}
}
class CardContainer extends React.Component {
constructor(props){
super(props)
this.state = {data: carddata};
this.destroy = this.destroy.bind(this);
}
destroy(elementKey){
console.log(elementKey)
debugger
let result = this.state.data.filter(item=> item.key !==elementKey);
this.setState({data: result});
}
render(){
return (<div>
Card Container
{this.state.data.map((card,index) => {
return <CardItem key={card.key} id={card.key} name={card.name} destroy={this.destroy}/>
})
}
</div>)
}
}

Related

How can i refresh my child componet by using a button click on parent componet?

I am new to this stackoverflow world. Please help me here. How can i refresh the child component based on the button click from the parent component. For example, i have a button in parent component called refresh and not passing any state variables or props to child component. but i want the child component to loaded again based on the button click of parent. I tried adding a state variable, but it was not updating the child component.
parent component:
import React from "react";
import ChildComponentForRefreshTesting from "./ChildComponentForRefreshTesting";
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { isRefreshClicked : false };
}
submit() {
this.setState({ isRefreshClicked: true }, () => this.setState({isRefreshClicked: false}));
}
render() {
return (
<div>
<h1>Parent Component ------<button onClick={this.submit}>Refresh</button></h1>
<ChildComponentForRefreshTesting />
</div>
)
}
}
export default MyComponent;
child component:
import React from 'react'
function ChildComponentForRefreshTesting() {
return (
<div>
child component
<br />
</div>
)
}
export default ChildComponentForRefreshTesting;
Changing state should re-render the current component and all the child components inside it.
I ran your code and there is a mistake with how you defined the setState method. You need to use arrow function, otherwise this will be undefined.
So change your submit button like following and it should work.
submit = () => {
this.setState({ isRefreshClicked: true });
};
Here's the stackblitz: https://stackblitz.com/edit/react-f5q3n8?file=src/MyComponent.js
In class components, you can call this.forceUpdate() method to force a rerender.
https://reactjs.org/docs/react-component.html#forceupdate

Props are empty on passing them to child class based components while filled when using functional component

It seems that props are not being passed to child component when my child component is a class based component. This is my parent component:
class ScreeningsList extends React.Component{
state = {screenings: [] };
componentDidMount = async () => {
const response = await apis.getAllScreenings();
this.setState({screenings: response.data});
}
render(){
return (
<div>
<ScrTest screeningsList = {this.state.screenings}/>
</div>
)
}
}
And here is my child component:
class ScrTest extends React.Component{
render(){
return (
<div className="screeningsContainer">
<h2>Title: {this.props.screeningsList._id}</h2>
</div>
)
}
}
Here I tried just to display id of the screening. The value in props did not exist. There were no props at all.
However when I use functional component and use the arrow function:
const ScreeningsToRender = props => {
...
}
I can access props by using props.screeningsList and use every value that is inside that prop. Rendering the component is succesfull and I can see the list of all the screenings. What should I do to recieve props properly in my child component?
You need a constructor in the child component:
class ScrTest extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div className="screeningsContainer">
<h2>Title: {this.props.screeningsList._id}</h2>
</div>
)
}
}
"When implementing the constructor for a React.Component subclass, you should call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor".
Source: https://reactjs.org/docs/react-component.html#constructor

Why componentWillReceiveProps is not called?

At child, I need to listen for state changed at parent, I tried to do so as:
Child
class deleteDriverAlert extends Component {
constructor(props) {
super(props);
this.state = {
show: false
};
}
componentWillReceiveProps(nextProps) {
console.log("componentWillReceiveProps . . . . .");
this.setState({ show: nextProps.dataset.showDeleteAll });
}
render() {
return (
<SweetAlert
warning
showCancel
confirmBtnText="Yes, delete it!"
confirmBtnBsStyle="danger"
cancelBtnBsStyle="default"
title="Are you sure?"
onConfirm={this.props.dataset.onConfirm}
onCancel={this.props.dataset.onCancel}
show={this.state.show}
>
You will not be able to recover this imaginary file!
</SweetAlert>
);
}
}
export default deleteDriverAlert;
then, in the parent, I add the child as:
<deleteDriverAlert data-showDeleteAll={this.state.show_delete_all} data-onConfirm={this.deleteDriver} data-onCancel={this.onCancelDelete} />
now, although I do change the property state show_delete_all at parent, componentWillReceiveProps is not called at child.
Any idea?
A few things, firstly you don't need to set the props into the state of the child component to be able to use them dynamically. The problem is most likely with the way you are changing the state in the parent.
Here is a simple example of the same thing you are trying to do:
The Parent component has its own state and a method to change it which is bound to the parent context and is flipped with a button. Then the state is passed to the child as a prop:
import React, { Component } from 'react';
import Child from './Child';
class Parent extends Component {
constructor(props) {
super(props);
this.state = { show: false };
this.flipShow = this.flipShow.bind(this);
}
flipShow(){
this.setState({show: !this.state.show})
}
render() {
return (
<div>
<p>Parent</p>
<button onClick={this.flipShow}>Show</button>
<Child show={this.state.show} />
</div>
);
}
}
export default Parent;
Then the child simply passes the prop through. Note: in the example below the componentWillReceiveProps is unnecessary but I only put it there to show that it does fire with this set up.
import React, { Component } from 'react';
import SweetAlert from './SweetAlert';
class Child extends Component {
componentWillReceiveProps(nextProps){
console.log("receiving new props");
}
render() {
return (
<SweetAlert
show={this.props.show}
/>
);
}
}
export default Child;
TL;DR
If componentWillReceiveProps isn't firing, it's a problem with the Parent component and the way it is setting the prop value not the child.
I may be wrong, but I don't think react will re-render the child component when the parent component change state, which makes sense because the state is a local thing specific to that component. But since you're not using a state management library it would make more sense to use the new React Context API in this scenario, to pass changing data down to the Child component, and it looks pretty straightforward
https://reactjs.org/docs/context.html

How to use Higher Order function (or alternative) for wrapping a React component without the component continually unmounting?

I have a React component (Parent) within which there is another componet (Child) that is wrapped using a Higher Order function (HOWrapper). The problem I am having is that each time the Parent component renders, the Child component unmounts and then re-mounts. I need to find a way that prevents the Child component from unmounting, but still continue to wrap it in a component whose name is dynamically assigned. I also want the option to pass additional parameters to the HOWrapper function, that may also be dynamically generated in the render() function of Parent. Any ideas?
Parent component:
import { HOWrapper } from './somepath';
import Child from './someotherpath';
export default class Parent extends Component {
...
render(){
let ChildWrapper = HOWrapper(Child);
return (
<ChildWrapper {...this.props} />
);
}
}
Higher Order function:
export function HOWrapper(WrappedComponent) {
return class Blanket extends Component {
constructor(props) {
super(props);
this.state = {
...
};
}
...
render() {
return (
<WrappedComponent
{...this.props}
/>
);
}
}
}
Because an HOC returns a component, a more typical approach to using them is once when exporting them, not on every render call.
let YourComponent = props => <div />
export default HOC(YourComponent)
Then if you want to do anything dynamic pass new props to it.
render() { return <YourComponent dynamicProps={foo} /> }

child of the component "this" value and how do I get to parent component?

child of the component "this" value and how do I get to parent component?
ex:
class AComponent extends Component{
static getThis(){
return this;
}
}
class MainComp extends Component{
componentDidMoud(){
console.log(AComponent.getThis());
}
}
in this way, how do I get it?
You shouldn't get the parent component from a child component. If you need to do something (ie affect parent component state), then pass a function from the parent to the child as a prop to do it. If you need to read something, then pass the relevant data from parent to child as a prop to read it.
You can pass props down to children, whether it be a simple primitive value for the child component to use, or a function that can be used by the child component to change the state of the parent component. Here's a simple example.
ParentComponent.js
import React, { Component } from 'react';
import ChildComponent from './ChildComponent';
class ParentComponent extends Component {
constructor(props) {
super(props);
this.state = {
someState: true
};
this.someFunction = this.someFunction.bind(this);
}
someFunction() {
this.setState({
someState: false
});
}
render() {
return (
<ChildComponent aFunc={this.someFunction} aString="someValue"/>
);
}
}
ChildComponent.js
import React, { Component } from 'react';
class ChildComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className={this.props.aString}>
<button onClick={this.props.aFunc}>
Some text
</button>
</div>
);
}
}

Resources