Ya hay varias respuestas excelentes, pero no creo que se hayan explicado muy bien y varios de los métodos proporcionados contienen algunas trampas que podrían hacer tropezar a las personas. Así que voy a repasar las tres formas principales (más una opción fuera del tema) para hacer esto y explicar los pros y los contras. Principalmente escribo esto porque la opción 1 se recomendó mucho y hay muchos problemas potenciales con esa opción si no se usa correctamente.
Opción 1: Representación condicional en el padre.
No me gusta este método a menos que solo vayas a representar el componente una vez y lo dejes allí. El problema es que hará que reaccione para crear el componente desde cero cada vez que cambie la visibilidad. Aquí está el ejemplo. LogoutButton o LoginButton se representan condicionalmente en el LoginControl primario. Si ejecuta esto, notará que se llama al constructor con cada clic en el botón. 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')
);
Ahora React es bastante rápido para crear componentes desde cero. Sin embargo, todavía tiene que llamar a su código al crearlo. Entonces, si el código de su constructor, componentDidMount, render, etc. es costoso, entonces se ralentizará significativamente mostrando el componente. También significa que no puede usar esto con componentes con estado donde desea que se conserve el estado cuando está oculto (y restaurado cuando se muestra). La única ventaja es que el componente oculto no se crea hasta que se selecciona. Por lo tanto, los componentes ocultos no retrasarán la carga de la página inicial. También puede haber casos en los que DESEA un componente con estado para restablecer cuando se alterna. En cuyo caso esta es tu mejor opción.
Opción 2: Representación condicional en el niño
Esto crea ambos componentes una vez. Luego, cortocircuita el resto del código de renderizado si el componente está oculto. También puede cortocircuitar otra lógica en otros métodos usando el accesorio visible. Observe el archivo console.log en la página de 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')
);
Ahora, si la lógica de inicialización es rápida y los hijos no tienen estado, entonces no verá una diferencia en el rendimiento o la funcionalidad. Sin embargo, ¿por qué hacer que React cree un componente nuevo cada vez que se alterna? Sin embargo, si la inicialización es costosa, la Opción 1 la ejecutará cada vez que active un componente que ralentizará la página al cambiar. La opción 2 ejecutará todos los inits del componente en la carga de la primera página. Retrasando esa primera carga. Debe tener en cuenta de nuevo. Si solo muestra el componente una vez en función de una condición y no lo alterna, o desea que se restablezca cuando se activa, entonces la Opción 1 está bien y probablemente sea la mejor opción.
Sin embargo, si la carga lenta de la página es un problema, significa que tiene un código costoso en un método de ciclo de vida y que generalmente no es una buena idea. Puede, y probablemente debería, resolver la carga lenta de la página moviendo el costoso código de los métodos del ciclo de vida. Muévalo a una función asíncrona iniciada por ComponentDidMount y haga que la devolución de llamada la ponga en una variable de estado con setState (). Si la variable de estado es nula y el componente es visible, haga que la función de representación devuelva un marcador de posición. De lo contrario, renderice los datos. De esa manera, la página se cargará rápidamente y llenará las pestañas a medida que se cargan. También puede mover la lógica al padre y enviar los resultados a los niños como accesorios. De esa manera, puede priorizar qué pestañas se cargan primero. O guarde en caché los resultados y solo ejecute la lógica la primera vez que se muestre un componente.
Opción 3: Ocultar clase
La ocultación de clases es probablemente la más fácil de implementar. Como se mencionó, simplemente crea una clase CSS con display: none y asigna la clase en función del accesorio. La desventaja es que se llama el código completo de cada componente oculto y todos los componentes ocultos están conectados al DOM. (La opción 1 no crea los componentes ocultos en absoluto. Y la opción 2 corta el código innecesario cuando el componente está oculto y elimina el componente del DOM por completo). Parece que esto es más rápido al alternar la visibilidad según algunas pruebas realizadas por los comentaristas en otras respuestas pero no puedo hablar de eso.
Opción 4: un componente pero cambiar los accesorios. O tal vez ningún componente en absoluto y caché HTML.
Esta no funcionará para todas las aplicaciones y está fuera de tema porque no se trata de ocultar componentes, pero podría ser una mejor solución para algunos casos de uso que la ocultación. Digamos que tienes pestañas. Es posible escribir un componente React y simplemente usar los accesorios para cambiar lo que se muestra en la pestaña. También puede guardar el JSX en variables de estado y usar un accesorio para decidir qué JSX devolver en la función de representación. Si se debe generar el JSX, hágalo y almacénelo en caché en el padre y envíe el correcto como accesorio. O genere en el niño y almacénelo en el estado del niño y use accesorios para seleccionar el activo.