Já existem várias ótimas respostas, mas não acho que tenham sido explicadas muito bem e vários dos métodos fornecidos contêm algumas dicas que podem enganar as pessoas. Então, vou abordar as três principais maneiras (mais uma opção fora do tópico) para fazer isso e explicar os prós e os contras. Estou escrevendo principalmente porque a Opção 1 foi muito recomendada e há muitos problemas em potencial com essa opção, se não for usada corretamente.
Opção 1: renderização condicional no pai.
Não gosto desse método, a menos que você só renderize o componente uma vez e o deixe lá. O problema é que isso fará com que o reagir crie o componente do zero toda vez que você alternar a visibilidade. Aqui está o exemplo. LogoutButton ou LoginButton estão sendo renderizados condicionalmente no LoginControl pai. Se você executar isso, notará que o construtor está sendo chamado a cada clique do botão. https://codepen.io/Kelnor/pen/LzPdpN?editors=1111
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
class LogoutButton extends React.Component{
constructor(props, context){
super(props, context)
console.log('created logout button');
}
render(){
return (
<button onClick={this.props.onClick}>
Logout
</button>
);
}
}
class LoginButton extends React.Component{
constructor(props, context){
super(props, context)
console.log('created login button');
}
render(){
return (
<button onClick={this.props.onClick}>
Login
</button>
);
}
}
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
Agora, o React é muito rápido na criação de componentes a partir do zero. No entanto, ele ainda precisa chamar seu código ao criá-lo. Portanto, se seu código de construtor, componentDidMount, render, etc for caro, diminuirá significativamente a exibição do componente. Isso também significa que você não pode usá-lo com componentes com estado em que deseja que o estado seja preservado quando oculto (e restaurado quando exibido.) A única vantagem é que o componente oculto não é criado, até que seja selecionado. Portanto, componentes ocultos não atrasarão o carregamento da sua página inicial. Também pode haver casos em que você QUER que um componente com estado seja redefinido quando alternado. Nesse caso, esta é sua melhor opção.
Opção 2: renderização condicional no filho
Isso cria os dois componentes uma vez. Em seguida, provoque um curto-circuito no restante do código de renderização se o componente estiver oculto. Você também pode causar um curto-circuito em outras lógicas em outros métodos usando o suporte visível. Observe o console.log na página codepen. https://codepen.io/Kelnor/pen/YrKaWZ?editors=0011
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
<LoginButton isLoggedIn={isLoggedIn} onClick={this.handleLoginClick}/>
<LogoutButton isLoggedIn={isLoggedIn} onClick={this.handleLogoutClick}/>
</div>
);
}
}
class LogoutButton extends React.Component{
constructor(props, context){
super(props, context)
console.log('created logout button');
}
render(){
if(!this.props.isLoggedIn){
return null;
}
return (
<button onClick={this.props.onClick}>
Logout
</button>
);
}
}
class LoginButton extends React.Component{
constructor(props, context){
super(props, context)
console.log('created login button');
}
render(){
if(this.props.isLoggedIn){
return null;
}
return (
<button onClick={this.props.onClick}>
Login
</button>
);
}
}
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
Agora, se a lógica de inicialização for rápida e os filhos estiverem sem estado, você não verá uma diferença no desempenho ou na funcionalidade. No entanto, por que fazer o React criar um novo componente a cada alternância? Se a inicialização for cara, a Opção 1 a executará toda vez que você alternar um componente que diminuirá a velocidade da página ao alternar. A opção 2 executará todas as entradas do componente no carregamento da primeira página. Abrandando a primeira carga. Deve notar novamente. Se você está apenas mostrando o componente uma vez com base em uma condição e não o está alternando, ou deseja que seja redefinido quando alternado, a opção 1 é boa e provavelmente a melhor opção.
Se o carregamento lento da página for um problema, significa que você tem um código caro em um método de ciclo de vida e isso geralmente não é uma boa ideia. Você pode, e provavelmente deveria, resolver o carregamento lento da página movendo o código caro dos métodos do ciclo de vida. Mova-o para uma função assíncrona iniciada por ComponentDidMount e faça com que o retorno de chamada o coloque em uma variável de estado com setState (). Se a variável state for nula e o componente estiver visível, faça com que a função render retorne um espaço reservado. Caso contrário, renderize os dados. Dessa forma, a página será carregada rapidamente e preencherá as guias à medida que forem carregadas. Você também pode mover a lógica para o pai e enviar os resultados aos filhos como acessórios. Dessa forma, você pode priorizar quais guias serão carregadas primeiro. Ou armazene em cache os resultados e execute a lógica apenas na primeira vez que um componente é mostrado.
Opção 3: ocultação de classe
Ocultar classes é provavelmente o mais fácil de implementar. Como mencionado, você acabou de criar uma classe CSS com display: none e atribuir a classe com base em prop. A desvantagem é que todo o código de cada componente oculto é chamado e todos os componentes ocultos são anexados ao DOM. (A opção 1 não cria os componentes ocultos. A opção 2 provoca um curto-circuito no código desnecessário quando o componente está oculto e remove o componente do DOM completamente.) Parece que é mais rápido alternar a visibilidade de acordo com alguns testes feitos por comentaristas. outras respostas, mas não posso falar com isso.
Opção 4: Um componente, mas altere Adereços. Ou talvez nenhum componente e cache de HTML.
Este não funcionará para todos os aplicativos e está fora de tópico porque não se trata de ocultar componentes, mas pode ser uma solução melhor para alguns casos de uso do que ocultar. Digamos que você tenha abas. Pode ser possível escrever um React Component e apenas usar os acessórios para alterar o que é exibido na guia. Você também pode salvar o JSX nas variáveis de estado e usar um suporte para decidir qual JSX retornar na função de renderização. Se o JSX precisar ser gerado, faça-o, armazene-o em cache no pai e envie o correto como suporte. Ou gere no filho e armazene em cache no estado do filho e use adereços para selecionar o ativo.