Jest już kilka świetnych odpowiedzi, ale nie sądzę, że zostały one wyjaśnione bardzo dobrze, a kilka z podanych metod zawiera pewne gotówki, które mogą wprawić ludzi w osłupienie. Omówię trzy główne sposoby (plus jedna opcja nie na temat), aby to zrobić i wyjaśnić zalety i wady. Piszę to głównie, ponieważ Opcja 1 była bardzo zalecana i istnieje wiele potencjalnych problemów z tą opcją, jeśli nie zostanie użyta poprawnie.
Opcja 1: Renderowanie warunkowe w obiekcie nadrzędnym.
Nie podoba mi się ta metoda, chyba że zamierzasz renderować komponent tylko raz i zostawić go tam. Problem polega na tym, że spowoduje to reakcję na tworzenie komponentu od zera za każdym razem, gdy zmienisz widoczność. Oto przykład. LogoutButton lub LoginButton są warunkowo renderowane w nadrzędnym LoginControl. Jeśli to uruchomisz, zauważysz, że konstruktor jest wywoływany przy każdym kliknięciu przycisku. 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')
);
Teraz React bardzo szybko tworzy komponenty od zera. Jednak nadal musi wywoływać kod podczas jego tworzenia. Więc jeśli twój konstruktor, składnik componentDidMount, renderowanie itp. Jest drogi, wówczas znacznie spowolni wyświetlanie komponentu. Oznacza to również, że nie można tego używać z komponentami stanowymi, w których chcesz zachować stan, gdy jest ukryty (i przywracany, gdy jest wyświetlany). Jedną zaletą jest to, że ukryty komponent nie jest tworzony, dopóki nie zostanie wybrany. Ukryte komponenty nie opóźnią początkowego ładowania strony. Mogą również wystąpić sytuacje, w których CHCESZ stanowy komponent zresetować po przełączeniu. W takim przypadku jest to najlepsza opcja.
Opcja 2: Renderowanie warunkowe u dziecka
To tworzy oba komponenty jeden raz. Następnie zewrzyj resztę kodu renderowania, jeśli komponent jest ukryty. Możesz także zwierać inną logikę innymi metodami, używając widocznego rekwizytu. Zwróć uwagę na plik console.log na stronie 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')
);
Teraz, jeśli logika inicjalizacji jest szybka, a dzieci są bezstanowe, nie zobaczysz różnicy w wydajności lub funkcjonalności. Dlaczego jednak React tworzy i tak nowy element przy każdym przełączaniu? Jeśli inicjalizacja jest jednak droga, opcja 1 uruchomi ją za każdym razem, gdy przełączysz komponent, co spowolni stronę podczas przełączania. Opcja 2 uruchomi wszystkie inicjały składnika przy ładowaniu pierwszej strony. Spowolnienie pierwszego obciążenia. Należy zanotować ponownie. Jeśli wyświetlasz komponent tylko raz w oparciu o warunek i nie przełączasz go, lub chcesz, aby zresetował się po przełączeniu, to opcja 1 jest w porządku i prawdopodobnie najlepsza opcja.
Jeśli jednak powolne ładowanie strony stanowi problem, oznacza to, że masz kosztowny kod w metodzie cyklu życia i ogólnie nie jest to dobry pomysł. Możesz i prawdopodobnie powinieneś rozwiązać powolne ładowanie strony, usuwając kosztowny kod z metod cyklu życia. Przenieś go do funkcji asynchronicznej uruchomionej przez ComponentDidMount, a wywołanie zwrotne umieść ją w zmiennej stanu za pomocą setState (). Jeśli zmienna stanu ma wartość NULL, a komponent jest widoczny, funkcja renderowania zwraca symbol zastępczy. W przeciwnym razie wyrenderuj dane. W ten sposób strona ładuje się szybko i zapełnia karty podczas ładowania. Możesz także przenieść logikę do rodzica i przekazać wyniki dzieciom jako rekwizyty. W ten sposób możesz ustalić, które karty będą ładowane jako pierwsze. Lub buforuj wyniki i uruchamiaj logikę tylko przy pierwszym wyświetleniu komponentu.
Opcja 3: Ukrywanie klas
Ukrywanie klas jest prawdopodobnie najłatwiejsze do wdrożenia. Jak wspomniano, po prostu tworzysz klasę CSS z display: none i przypisujesz klasę na podstawie prop. Minusem jest to, że wywoływany jest cały kod każdego ukrytego komponentu, a wszystkie ukryte komponenty są dołączane do DOM. (Opcja 1 w ogóle nie tworzy ukrytych komponentów. Opcja 2 powoduje zwarcie niepotrzebnego kodu, gdy komponent jest ukryty i całkowicie usuwa komponent z DOM). Wygląda na to, że szybsze przełączanie widoczności jest szybsze według niektórych testów przeprowadzonych przez komentujących inne odpowiedzi, ale nie mogę z tym rozmawiać.
Opcja 4: jeden element, ale zmień rekwizyty. A może żaden komponent i buforuj HTML.
Ten nie będzie działał dla każdej aplikacji i jest nie na temat, ponieważ nie dotyczy ukrywania komponentów, ale może być lepszym rozwiązaniem w niektórych przypadkach użycia niż ukrywanie. Powiedzmy, że masz karty. Może być możliwe napisanie jednego React Component i po prostu użycie rekwizytów, aby zmienić to, co wyświetla się na karcie. Możesz także zapisać JSX do zmiennych stanu i użyć rekwizytu, aby zdecydować, który JSX ma zostać zwrócony w funkcji renderowania. Jeśli JSX musi zostać wygenerowany, zrób to i buforuj go w obiekcie nadrzędnym i wyślij poprawny jako rekwizyt. Lub wygeneruj w dziecku i buforuj go w stanie dziecka i użyj rekwizytów, aby wybrać aktywny.