Here I have created a toggle button re-rendering in parent components and in child components a plus button, and the counter requirement is that the toggle button re-rendering is a toggle button that will hide and show the components, but if any last counter is added, for example, from 0 to 2, after hiding and showing it should remain the same, like 2 and not 0, but the problem is that I am not able to hide the child components, so how do I hide and show the child components and maintain the child state?
Basically, by rendering the parent, I want to keep maintaining the child state value.
parent code is
import React, { useRef, useState, useMemo } from 'react';
import DropDown from './DropDown';
function App() {
const shouldRenderChild = useRef(true);
const [hide, setHide] = useState(false);
const toggleChildRendering = () => {
shouldRenderChild.current = !shouldRenderChild.current;
setHide(!hide);
};
const MemoizedDropDown = useMemo(() => {
return shouldRenderChild.current ? <DropDown /> : null;
}, []);
return (
<div>
<button onClick={toggleChildRendering}>
Toggle Child Rendering
</button>
{MemoizedDropDown}
</div>
);
}
export default App;
child code is
import React, { useState } from "react";
export default function DropDown() {
const [number, setNumber] = useState(0);
return (
<>
<button onClick={() => setNumber(number + 1)}>+</button>
<div>Child Component{number}</div>
</>
);
}
>Solution :
Every time component is mounted or unmounted (using conditional rendering) – state of the component is re-setting itself to default values. So that is your problem, and useMemo
hook will not help you here.
To solve your issue you can modify your root css files and add something like .hidden
class:
.hidden {
display: none;
}
Most probably you already have that kind of utility classes in your project. Like d-none
for bootstrap or similar.
Next – you need to add a wrapper to your DropDown
component, or change the type of root node that is returned by this component to something else than React.Fragment
ie <> </>
and to apply conditional className
on it like this:
className={hide ? 'hidden' : ''}
Here is an example of the solution:
import React, { useState } from 'react';
function DropDown({ className }) {
const [number, setNumber] = useState(0);
return (
<div className={className}>
<button onClick={() => setNumber(number + 1)}>+</button>
<div>Child Component: {number}</div>
</div>
);
}
export const App = () => {
const [hide, setHide] = useState(false);
const toggleChildRendering = () => {
setHide(!hide);
};
return (
<div>
<button onClick={toggleChildRendering}>Toggle Child Rendering</button>
<DropDown className={hide ? 'hidden' : ''} />
</div>
);
};
Stackblitz demo