Уже есть несколько хороших ответов, но я не думаю, что они были объяснены очень хорошо, и некоторые из приведенных методов содержат некоторые ошибки, которые могут сбить людей с толку. Итак, я собираюсь перейти к трем основным способам (плюс один не по теме), чтобы сделать это, и объяснить плюсы и минусы. Я в основном пишу это, потому что вариант 1 был рекомендован, и есть много потенциальных проблем с этим вариантом, если он не используется правильно.
Вариант 1: условный рендеринг в родительском.
Мне не нравится этот метод, если только вы не собираетесь визуализировать компонент один раз и оставить его там. Проблема заключается в том, что каждый раз при переключении видимости вы будете реагировать на создание компонента с нуля. Вот пример. LogoutButton или LoginButton условно отображаются в родительском LoginControl. Если вы запустите это, вы заметите, что конструктор вызывается при каждом нажатии кнопки. 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')
);
Теперь React довольно быстро создает компоненты с нуля. Тем не менее, он все равно должен вызывать ваш код при его создании. Так что если ваш конструктор, componentDidMount, рендер и т. Д. Код дорогой, то он будет значительно замедлять показ компонента. Это также означает, что вы не можете использовать это с компонентами с состоянием, где вы хотите, чтобы состояние сохранялось при скрытии (и восстанавливалось при отображении.) Одно преимущество заключается в том, что скрытый компонент вообще не создается до тех пор, пока он не выбран. Таким образом, скрытые компоненты не будут задерживать вашу начальную загрузку страницы. Также могут быть случаи, когда вы хотите, чтобы компонент с состоянием сбрасывался при переключении. В этом случае это ваш лучший вариант.
Вариант 2: условный рендеринг у ребенка
Это создает оба компонента один раз. Затем замыкает остальную часть кода рендеринга, если компонент скрыт. Вы также можете закоротить другую логику в других методах, используя видимую опору. Обратите внимание на файл console.log на странице кода. 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')
);
Теперь, если логика инициализации быстрая, а дочерние элементы не сохраняют состояния, вы не увидите разницы в производительности или функциональности. Однако зачем в любом случае заставлять React создавать новый компонент, каждый раз переключаясь? Однако если инициализация стоит дорого, вариант 1 будет запускать ее каждый раз, когда вы переключаете компонент, что замедляет страницу при переключении. Вариант 2 будет запускать все компоненты компонента при первой загрузке страницы. Замедление первой загрузки. Должен заметить еще раз. Если вы просто показываете компонент один раз на основе условия, а не переключаете его, или вы хотите, чтобы он сбрасывался при переключении toggledm, тогда вариант 1 подойдет и, вероятно, будет лучшим вариантом.
Однако, если медленная загрузка страницы является проблемой, это означает, что у вас есть дорогой код в методе жизненного цикла, и это, как правило, не очень хорошая идея. Вы можете и, вероятно, должны решить проблему медленной загрузки страницы, удалив дорогой код из методов жизненного цикла. Переместите его в асинхронную функцию, которая запускается ComponentDidMount, и пусть обратный вызов помещает ее в переменную состояния с помощью setState (). Если переменная состояния равна нулю, а компонент видим, тогда пусть функция рендеринга возвращает заполнитель. В противном случае визуализируйте данные. Таким образом, страница будет загружаться быстро и заполнять вкладки по мере их загрузки. Вы также можете переместить логику в родительский элемент и передать результаты дочерним элементам в качестве реквизита. Таким образом, вы можете определить приоритетность вкладок, которые будут загружены первыми. Или кэшируйте результаты и запускайте логику только при первом показе компонента.
Вариант 3: скрытие класса
Скрытие классов, вероятно, проще всего реализовать. Как уже упоминалось, вы просто создаете класс CSS с display: none и назначаете класс на основе prop. Недостатком является то, что весь код каждого скрытого компонента вызывается, и все скрытые компоненты присоединяются к DOM. (Вариант 1 вообще не создает скрытых компонентов. А Вариант 2 замыкает ненужный код, когда компонент скрыт, и полностью удаляет компонент из DOM.) Кажется, это быстрее при переключении видимости в соответствии с некоторыми тестами, выполненными комментаторами на другие ответы, но я не могу говорить с этим.
Вариант 4: один компонент, но изменить реквизит. Или, может быть, нет компонента вообще и кешировать HTML.
Это не будет работать для каждого приложения, и это не по теме, потому что речь не идет о скрытии компонентов, но может быть лучшим решением для некоторых случаев использования, чем скрытие. Допустим, у вас есть вкладки. Может быть возможно написать один React Component и просто использовать реквизит, чтобы изменить то, что отображается на вкладке. Вы также можете сохранить JSX для переменных состояния и использовать опору, чтобы решить, какой JSX вернуть в функции рендеринга. Если JSX должен быть сгенерирован, тогда сделайте это и кешируйте его в родительском и отправьте правильный как опору. Или сгенерируйте в дочернем элементе и кэшируйте его в дочернем состоянии и используйте реквизиты для выбора активного.