redux is dispatching prevState value in react hooks - reactjs

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

Related

React parent to child props passing without rerender

I have a button on my parent component and a third-party form in a child component. When the user clicks the button, the save function in the child component should run. This is my plan.
Method 1 I tried:
1.Created a variable on parent called save.
2. When button is clicked, save becomes true
3. Save is passed down to the child as props
4. Child contains a useEffect() which listens to changes in props.save
5. If props.save is true, save function of child component runs
Method 2 I tried:
Instead of passing props, I created a react-redux store.
The store contains save variable which is false by default
When button is clicked, save in redux becomes true
I use useSelector() hook to listen to the save variable change, inside the child component
UseEffect is used to run the save() function when the value change is detected
What happens with both methods is that I am losing the data in my child component because the variable change in the parent causes a page refresh. Therefore I want to pass the data down to the child, without causing rerenders. What are the options I have?
Thanks in advance
Thanks to #Shyam, I could finally solve this issue!
My assumption that useState and props cause render was correct. And as #Shyam suggested, there is no direct way to avoid it.
I am using react-editor-js in my project and that's what caused the issue
<EditorJs
instanceRef={()=>{//code to save the reference as state variable}}
enableReInitialize
data={{}}
tools={EDITOR_JS_TOOLS}
/>
The reason for state loss was that my instanceRef was being reassigned every time the component renders.
This reassignment can be prevented by wrapping the method to save the reference as a state variable with useCallback()

Re-render React component after props change

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.

How to trigger useEffect when a subcomponent renders?

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

Does React Redux recreate the entire Virtual DOM each time an action is dispatched from the Store?

Isn't that a very expensive affair?
For example, if I clicked a button that toggles something... Does React need to recreate the entire Virtual DOM just for that one action and diff it as well?
When you call React Redux's connect on components, you're wrapping them in a component called Connect. The component reads the store from the <Provider>'s context. When you dispatch an action, the Redux store gets updated, which causes all connect-ed components to get new props (those defined in mapStateToProps during a store update.
If a connected component subscribes to a store field but the action doesn't change that field's value, it wouldn't re-render.
The rest follows regular React rendering rules. If a connected component's HOC wrapper subscribes to a store field that has changed, it will update and cause the connected component to re-render as well. You could implement shouldComponentUpdate in the connected component if you don't want it to re-render.
References:
https://github.com/reduxjs/react-redux/blob/master/src/components/Provider.js
https://github.com/reduxjs/react-redux/blob/master/src/components/connectAdvanced.js

Why is componentWillUnmount firing after next components componentWillMount?

I have a React/Redux application with two components. I need to clear a portion of redux state when the first component unmounts, because the second component will error with the state in that form. I've tried to dispatch an action clearing the chunk of state when the first component unmounts, but the second component begins mounting before the first components componentWillUnmount method is called. When I view dispatched actions in redux-logger, I see the second component dispatching actions from componentWillMount and then componentWillUnmount actions from the previous component called.
This is not the expected behavior is it? I am also using react-router v4. Thanks!
Since React v16, the componentWillUnmount hook can fire asynchronously.
This means that you can't make any assumptions about the order (or timings) of the invocations of these hooks cross-component.

Resources