Aqui eu criei uma re-renderização do botão de alternância nos componentes pai e um botão de adição nos componentes filhos, e o requisito do contador é que a re-renderização do botão de alternância seja um botão de alternância que ocultará e mostrará os componentes, mas se houver, o último contador é adicionado, por exemplo, de 0 a 2, depois de ocultar e mostrar deve permanecer o mesmo, tipo 2 e não 0, mas o problema é que não estou conseguindo ocultar os componentes filhos, então como faço para ocultar e mostrar o componentes filhos e manter o estado filho? Basicamente, ao renderizar o pai, quero continuar mantendo o valor do estado filho. código pai é
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;
código filho é
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>
</>
);
}
Cada vez que o componente é montado ou desmontado (usando renderização condicional) - o estado do componente é redefinido para os valores padrão. Então esse é o seu problema, e
useMemo
o hook não irá ajudá-lo aqui.Para resolver seu problema, você pode modificar seus arquivos CSS raiz e adicionar algo como
.hidden
class:Muito provavelmente você já possui esse tipo de classe utilitária em seu projeto. Como
d-none
para bootstrap ou similar.Em seguida - você precisa adicionar um wrapper ao seu
DropDown
componente ou alterar o tipo de nó raiz retornado por este componente para algo diferente deReact.Fragment
ie<> </>
e aplicar condicionalclassName
a ele assim:Aqui está um exemplo da solução:
Demonstração Stackblitz
O principal problema da sua abordagem é que você está usando
useMemo
da maneira errada.useMemo
armazena em cache um valor calculado (neste caso, um componente) e só recalculará esse valor se uma de suas dependências for alterada. Você deve usaruseMemo
para decidir se renderiza ou não oDropDown
componente e, como dependência para essa decisão, usehide
.Aqui está uma solução mais detalhada:
Componente pai: usaremos
hide
como estado para determinar se devemos mostrar ao filho. UsaremosuseMemo
para armazenar em cache o componente filho. Sehide
mudar, ele irá recalcular se deve mostrar o componente filho.Componente filho: permanece o mesmo. Simplesmente mostra um botão para incrementar um contador.
Seguindo esta abordagem, você pode mostrar/ocultar o componente filho sem que ele perca seu estado interno. Entretanto, observe que se o componente filho for desmontado (ou seja, completamente removido do DOM) e depois remontado, seu estado interno será redefinido. Se quiser persistir o estado mesmo que o componente esteja desmontado, você precisará de uma solução mais complexa, como usar contexto ou mover o estado para o componente pai e passá-lo como acessórios.
A solução simples para isto é Elevar o Estado .
!hide ? <DropDown /> : null
, ele será desmontado quandohide
for verdadeiro.number
estado da criança, ele também desaparecerá.number
valor no estado pai, ele persistirá.hide
sinalizador ser verdadeiro, você ainda terá o estado salvo em parent .hide
sinalizador para definir o estilo do componente filho paradisplay: none
<Estilo suspenso={{ display: ocultar? 'nenhum' : 'bloquear' }} ... />
O caminho certo:
Aplicativo.js
Lista suspensa.js