Reputation: 525
See codebox. https://codesandbox.io/s/component-issue-snj24?file=/src/App.js:0-1254
Whenever Main re-renders, the current component rendered conditionally though the switch will have its state reset const [value, setValue] = React.useState(0)
.
If I took any of the components (comp1, comp2, comp3) and inserted it into the main return (replacing ) this does not occur.
-- Update As noticed by Dennis, its due to function being nested. Alternative https://codesandbox.io/s/component-issue-forked-uejy1
Upvotes: 1
Views: 2611
Reputation: 1712
I had this problem recently. As Dennis said, it is due to function redefinition. Eventually I figured out that this problem could be solved by a very minor change.
Just change the JSX instantiation to a JSX expression (General function call):
from
<RenderActivePage />
to
{ RenderActivePage() }
Because it's not instantiated using JSX, React will not manage the lifecycle of the RenderActivePage
element itself.
That is, it won't treat RenderActivePage
as an element, but will simply output the result of this function.
This approach actually has the same effect as inlining an expression in return:
return (
<div className="App">
<h2>Pressing "update main component" resets child state</h2>
<button onClick={() => setValue(value + 1)}>update main component</button>
{(() => {
switch (activePage) {
case 0:
return <Comp1 />;
case 1:
return <Comp2 />;
default:
return <div></div>;
}
})()}
</div>
);
Upvotes: 0
Reputation: 53
I know this was already answered a while ago but the answer helped me solve my problem and so just wanted to add my 2 cents. It seems like when a child component is inside any condition in a parent, for example :
{ isTrue && <ChildComponent/> }
// or
{ isTrue ? <ChildComponent1/> : <ChildComponent2/> }
or a switch like above then the child component is unmounted and re-mounted on every re-render of the parent. This ends up resetting the local state in the child component on every re-render of the parent.
To solve this problem, I ended up passing the condition to the child as a prop i.e <ChildComponent isTrue={isTrue} />
and then conditionally rendering inside the child.
Upvotes: 2
Reputation: 53944
The component does not "re-render" it unmounts, because you declared RenderActivePage
in function's body, on every render it re-assigned, meaning it re-mounts on every render.
export default function App() {
// remounts on every render
const RenderActivePage = () => {
switch (activePage) {
case 0:
return <Comp1 />;
case 1:
return <Comp2 />;
default:
return <div></div>;
}
};
return (
<div className="App">
<RenderActivePage />
</div>
);
}
Upvotes: 1