Find out from parent component that child component is mounted in react - reactjs

I have a react component, which has a child component. I have to know in parent component that the child component is mounted. How to do that?

This depends on the version of React you are using.
If you are using React version 16.8 or higher, you can use the useEffect hook in the child component which can trigger a function in the parent component.
const Parent = props => {
const OnChildMount = () => {
console.log('Child Mounted);
}
return (
<Child onMount={OnChildMount}/>
)
}
const Child = props => {
useEffect(() => {
props.onMount();
}, []);
return (
//The child JSX
);
}
The empty brackets [] in the useEffect hook makes sure that it only runs when the Child component is mounted.
If you are using older versions of React, you can use the ComponentDidMount lifecycle hook in the child component to trigger the same function in the Parent.
This being said, the final solution would actually depend on your exact requirement.

Related

useMemo function is getting executed even though the dependency didnt change

I have a parent component which renders everytime data in the react query changes. It is using a child component to which it passes data which should render some cards.
Inside the child component, I used the useMemo() function to make sure if it receives the same data as previously it wouldnt execute the rendering of all the cards.
This is the child component
export const VerticalCardsList = (props : VerticalCardsProps) => {
const VerticalCards = useMemo(() => {
console.log('Executing the useMemo function')
}, [props.verticalCardsData])
return VerticalCards }
The parent component calls this in a way like this
<VerticalCardsList verticalCardsData={props?.cardsResponse?.data?} />

Does React know not to re-render child when parent changes?

<Parent P={some_state} >
<Child />
<Parent />
If some_state changes, causing the Parent to re-render, does it know to leave Child alone?
React Memo
I think what you are looking for is React.memo. Memoizing a component tells the component not to change or render unless the props it cares about changes or it has it's own internal changes.
In your example, if someState changes in the <Parent /> the <Child /> will render again. To fix that we can memoize our child.
Example Implementation
// Child Component
import React, { useEffect } from "react";
const Child = () => {
useEffect(() => console.log("Child rendered")); // simple way of logging each time the component renders
return (
<span>
I take no props, I shouldn't update unless my local state changes
</span>
)
};
const MemomizedChild = React.memo(Child);
// Parent Component
const Parent = ({ someState }) => {
return (
<MemomizedChild />
)
};
// Parent of Parent Component
import { useEffect, useState } from "react";
const App = () => {
const [foobar, setFoobar] = useState("hello");
useEffect(() => {
setTimeout(() => setFoobar("world"), 5000)
}, []) // after 5 seconds change the state variable to "world"
return (
<Parent someState={foobar} />
)
}
Explanation
Here are the steps or chain of events in that example:
App component has a local state variable foobar (just to trigger a prop change in the Parent component)
After five seconds the Parent's someState will change
Normally would trigger a render from the Child
We memoized Child so we should only see that "Child rendered" console log once
If we use the non memoized Child component the "Child rendered" console log will fire twice, once on mount and the second time when the Parent props change.

React useCallback() function in Parent is only working fine with Child if React.memo is used, without it not working

Parent Component
The parent component contains input which on change sets the state "local" and a button which on click takes this "local" state's value and sets it to "sendLocal"
Functions
changehandler : triggers on input type change.
sendLocalValue : takes "local" value puts it into "sendLocal" variable triggers on button click.
sendValue : this memoized function with dependeny "sendLocal" is passed on as a prop in child component triggers once the child is rendered.
import React, { useState, useCallback } from "react";
import ChildComponent from "./ChildComponent";
function ParentComponent() {
const [local, setLocal] = useState();
const [sendLocal, setsendLocal] = useState();
const changehandler = (e) => {
console.log("parent");
setLocal(e.target.value);
};
const sendLocalValue = () => {
setsendLocal(local);
};
const sendValue = useCallback(() => {
return sendLocal;
}, [sendLocal]);
return (
<>
<input type="text" onChange={changehandler} defaultValue={local} />
<button onClick={sendLocalValue}>send</button>
<ChildComponent getValue={sendValue} />
</>
);
}
export default ParentComponent;
Child Component
getValue prop calls the memoized "sendValue" function of parent which returns the value of sendLocal.
Problem
Everything works fine,the child component renders only when the "sendLocal" value changes on button click but if i remove React.memo() in child both the component render on input type change even with useCallback() used, why?
import React, { useEffect, useState } from "react";
function ChildComponent({ getValue }) {
console.log("child");
return <div>child's {getValue()}</div>;
}
export default React.memo(ChildComponent);
There is a general misconception that React components rerender when props or state change. while this is partially true, can lead to misunderstoods: a react component rerenders when its state changes or when its parent rerenders (because its state changed or because its parent rerendered, and so on).
So this means that every time ParentComponent rerenders, all its (non memoized) children will rerender.
To avoid this, you can use React.memo or React.PureComponent.
You can verify that by removing React.memo and not passing any props to the ChildComponent. Even with no props, it will rerender every time its parent rerenders.
when the parent re-renders, the whole props object for the child is created as a new object, which leads to the child re-render.
it does not matter that you have memoized all the different individual props, you have to memoize the component itself so that it does not re-render when the whole props object changes.
In this case, it also means that you still have to memoize the function as well as the child component, because React.memo only does a shallow comparison of individual props.

setState triggers child UseEffect with props as dependency

I have a component which receives as a prop a setState hook from its parent component. When it calls that prop causes a re-render since parent updates its state.
The thing is that I have a useEffect inside the child component that needs to be run only when props change (props is the only dependency it has). But since its parent re-renders it will be executed even when it's not need and I don't know a way to prevent it. I think parent rerender send the props again to the child.
Attaching a basic reproduction of my issue
function Parent = () => {
const [test, setTest] = useState()
return (
<Child onClick={value => setTest(value)} propINeed={{foo: 'bar'}}/>
)
}
function Child = props => {
useEffect(() => {
//STUFF I NEED TO RUN ONLY WHEN PROPS DO REALLY CHANGE
}, [props])
//ONCLICK PROP IS CALLED, AND useEffect RUNS AGAIN, messing with my data
}
I know props don't change. So I'm pretty sure it's due to the parent re-render
Put only the propINeed into the dependency array, so the useEffect callback doesn't run on click:
useEffect(() => {
//STUFF I NEED TO RUN ONLY WHEN PROPS DO REALLY CHANGE
}, [props.propINeed])

Unmounting a component when triggered through parent component

I have a parent component and child component. Child component will be rendered through parent based on a condition. So, when child gets rendered, all useEffect and other code gets executed and I'm able to achieve componentDidMount kind of methods. I'm not directly accessing child component but only use Parent to render it based on parent's props.
Once my child component is visible, I call a method which resets 'doesChildExists' prop and re-render ParentComponent and since the condition is failed, ChildComponent is not rendered (unmounted). Once, ChildComponent is about to unmount, I need to do some stuff, but existing useEffect doesn't seem to get called. How do I handle this? Please help!!
Please, let me know if this is not the right approach, and I have handle rendering of child in a different way.
const ChildComponent: FunctionComponent<Props> = (props: Props) => {
useEffect(() => {
return () => {
// handle unmount
}
}, []);
return (
<div class='textDiv'>
This is content
</div>
)
}
const ParentComponent: FunctionComponent<ParentProps> = (props: ParentProps) => {
return (
<>
{doesChildExists &&
createPortal(<ChildComponent />, document.body)}
</>
)
}

Resources