I know we can trigger the useEffect hook either:
Every time the component renders.
When the component mounts and/or unmounts.
When one of the defined dependencies changes.
But is it possible to trigger it when a subcomponent renders?
you can pass a function as prop to the child component and use a useEffect inside the child so that every time it renders again you can run the prop function
One way you can do is to pass a callback to child compon3ent which would be invoked with each child component render. Now this callback would be updating one of the prop of parent component with your hook. Your hook can specify this prop as its dependency which means every time it changes, your hook be triggered. This would ensure you have your hook inside parent component only but the problem is hook would trigger parent component re-render and you are stuck in a loop. From what I can understand, you don't need a hook but something that keeps an eye on every render of child component and does something. A simple callback should be enough in this case
Related
I have a need in my app where I am sending data in child component to parent component onChange of a field, when the child component unmounts I want to send the complete data to redux, and when the child component mounts again, I want to preload it from redux.
In my implementation I am doing this by sending data to parent component, and on unmount I have passed a callback in which parent component dispatches the state to redux, and when child component mounts again, I have used useSelector to get the redux value.
But the problem I am facing is redux is dispatching prevState value rather than updated value. When I unmount the component the second time, updated value is dispatched
I am attaching the codesandbox link
https://codesandbox.io/s/react-redux-with-hooks-forked-hp79o?file=/src/App.js
Steps to reproduce:
Type your name and email in the textbox.
Click on unmount button to unmount the child component.(Dispatched value will be empty)
Click on unmount button again to mount the child component. (Textbox will not be prefilled)
Click on unmount again to unmount. (This time the dispatched value will be name and email which were written)
Click on mount again to mount. (Textbox will be prefilled as values were dispatched this time).
I don't know where I am going wrong.
You need to use combination of useRef and useEffect to make current state changes available to use effect during unmount
This is explained here
https://www.timveletta.com/blog/2020-07-14-accessing-react-state-in-your-component-cleanup-with-hooks/
Updated codesandbox code which works is here
https://codesandbox.io/s/react-redux-with-hooks-forked-gymhl?file=/src/Unmounted.js
In the React docs, it says
By default, when your component’s state or props change, your component will re-render.
I understand for state changes, but I am not sure about when props change. As far as I am aware, props are always passed from the parent component to the child component. And when the parent component re-renders (due to a state change, for example), all child components also re-render (ignoring shouldComponentUpdate). So it seems to me that if the parent component re-renders, all child components will re-render regardless of whether I am passing new props to them or not. If I do pass new props to the child component, the fact the child re-renders is simply because the parent is re-rendering, not because I am passing new props.
Is there a scenario where a parent component passes new props to a child component, causing the child component to re-render, but it is not caused simply by the parent component re-rendering?
Is it possible to see an example where a component will re-render because it receives new props, rather than because the parent is re-rendering (or its own state changed)?
Sorry if this is a basic question, I am new to React.
EDIT: I see that Redux can cause components to re-render by passing new props, I'm curious to know what Redux is doing behind the scenes to achieve this.
To answer the question you ask at the end:
If the child is a PureComponent or wrapped in React.memo it will only re-render if the props change. If the parent re-renders then the component will compare the props it receives and if they're identical to the previously passed props it will not re-render.
If the child is not a PureComponent or wrapped in React.memo then it will re-render any time its parent re-renders.
I‘m not new to react and was asking the same thing. There was an article which made it clear for me: https://thoughtbot.com/blog/react-rendering-misconception
The re-render is needed for diff-checking if DOM updates are necessary. If you‘ve implemented shouldComponentUpdate or wrapped with memo (both returning false), then rerender is skipped.
If a child component is connected using redux or context, then it might rerender even without parent being rerendered.
When you use provider, or HOC, or Redux with mapStateToProps for example, the props are changed from other component injecting props.
Connect middleware of redux is similar to subscription, each child component can directly connect to the store through subscription, and whenever the store changes, the store tries to resync all its connected components. New incoming data to any component comes as props resulting in re-render.
Any component getting changed from outside of its state can be through props only, so it is similar to a parent component passing new data / redux store pushing new data to the component.
Is something like method working like ComponentDidMount, but is calling just in the first mounting not for every?
No, there is not function like this. However, you can keep track of how many times a component mounts in its parent state and with a callback function. Alternatively, the parent can send a flag that indicates what the child should render.
Are there any hooks fired off when one of the components children is removed (not rendered due to conditional) and then added back again? The change happens due to state update somewhere above the component tree, but I would like to intercept it somehow on half way up.
For some reason I had an impression that componentDidUpdate should fire in such case, but now I see that it only goes off when update happens to the components state or the state of one of its children...?
Each component has several “lifecycle methods” that you can override to run code at particular times in the process.
The three lifecycle methods are mounting, updating and unmounting.
Updating
An update can be caused by changes to props or state. These methods are called when a component is being re-rendered
So when a child component is not rendered it doesn't fall in any of these categories, ie mounting, unmounting or updating. Lifecycle method exists for components and any change that happens in the child components does not affect the parent component lifecycle methods in any way.
For updating to happen for a particular component, as mentioned above a change in state or props of that particular component has to happen
Read The Component Lifecycle from react docs.
I have a component, and its componentDidUpdate seems to trigger for no reason. It's a child component, has no state. Even though the prevProps and this.props are the exact same its triggering, is there any reason for this? I thought update should only trigger when there is a change in the props/state?
componentDidUpdate() is fired every time the parent component re-renders (and passes in new props). And in stateful components also whenever setState() is fired.
Even if old prevprops and this.props are exactly the same, componentDidUpdate() is still fired if the parent component re-renders.
If you want to prevent react to enter a render cycle, you should implement the shouldComponentUpdate() method, where you can compare new and old props.
update should only trigger when there is a change in the props/state
No, React renders to VirtualDOM everything each time. But then it updates only changed properties in real DOM.
To avoid that you can use PureRenderMixin or your custom comparation code in shouldComponentUpdate.