Показать или скрыть элемент в React

337

Я впервые общаюсь с React.js и не могу найти способ показать или скрыть что-то на странице с помощью события click. Я не загружаю какую-либо другую библиотеку на страницу, поэтому я ищу какой-то собственный способ, используя библиотеку React. Это то, что у меня есть до сих пор. Я хочу показать результаты div при срабатывании события click.

var Search= React.createClass({
    handleClick: function (event) {
        console.log(this.prop);
    },
    render: function () {
        return (
            <div className="date-range">
                <input type="submit" value="Search" onClick={this.handleClick} />
            </div>
        );
    }
});

var Results = React.createClass({
    render: function () {
        return (
            <div id="results" className="search-results">
                Some Results
            </div>
        );
    }
});

React.renderComponent(<Search /> , document.body);
  • 7
    В принятом комментарии используется новая технология, чтобы делать то, что существующие технологии на нативном уровне могут делать проще, быстрее и совместно с другими языками и библиотеками. Обработка этого со стандартным CSS почти наверняка лучший ответ.
  • 7
    @JohnHaugeland, лучший ответ при использовании React Framework - это принятый ответ, охватывающий весь стиль React, в котором есть функции очистки, которые в некоторых случаях необходимо выполнять. Это не очень хорошая практика, когда компоненты просто прячутся в темноте. Если вы смешиваете что-то, вы лучше становитесь все нативным, что всегда быстрее, чем все остальное.
Показать ещё 4 комментария
Теги:

16 ответов

382
Лучший ответ

Ключ должен обновить состояние компонента в обработчике кликов с помощью setState. Когда применяются изменения состояния, метод render снова вызывается с новым состоянием:

var Search = React.createClass({
    getInitialState: function() {
        return { showResults: false };
    },
    onClick: function() {
        this.setState({ showResults: true });
    },
    render: function() {
        return (
            <div>
                <input type="submit" value="Search" onClick={this.onClick} />
                { this.state.showResults ? <Results /> : null }
            </div>
        );
    }
});

var Results = React.createClass({
    render: function() {
        return (
            <div id="results" className="search-results">
                Some Results
            </div>
        );
    }
});

ReactDOM.render(<Search />, document.getElementById('container'));

http://jsfiddle.net/kb3gN/15084/

  • 3
    Да, хороший момент о состоянии против реквизита. Лучший способ сделать это, как в учебном пособии, где панель поиска и таблица результатов - это братья и сестры, а не помещать результаты в поиск: facebook.github.io/react/docs/thinking-in-react.html
  • 40
    Как отмечено в другом ответе, вставка / удаление намного медленнее, чем простая маскировка классов.
Показать ещё 3 комментария
172
<style type="text/css">
    .hidden { display:none; }
</style>
render: function() {
    return (
      <div className={this.props.shouldHide ? 'hidden' : ''}>
        This will be hidden if you set <tt>props.shouldHide</tt> 
        to something truthy.
      </div>
    );
}
  • 10
    Лучше условно вернуть ноль, как в ответе Дугласа. Это позволяет React полностью удалить его из DOM. В вашем случае div и его содержимое все еще находятся в DOM, но не отображаются. Это может повлиять на производительность.
  • 98
    Влияние на производительность гораздо хуже для добавления и удаления элемента dom, чем для его скрытия и показа. Я осознаю разницу между его подходом и моим, и я считаю, что вы абсолютно не правы. Пожалуйста, подумайте о том, чтобы найти время, чтобы определить «последствия для производительности» и затем измерить его.
Показать ещё 11 комментариев
72

Вот альтернативный синтаксис для тернарного оператора:

{ this.state.showMyComponent ? <MyComponent /> : null }

эквивалентно:

{ this.state.showMyComponent && <MyComponent /> }

Lean why


Также альтернативный синтаксис с display: 'none';

<MyComponent style={this.state.showMyComponent ? {} : { display: 'none' }} />

Однако, если вы злоупотребляете display: 'none', это приводит к загрязнению DOM и, в конечном счете, замедляет ваше приложение.

37

Вот мой подход с использованием ES6. Хотя принятый ответ верен, он довольно устарел.

import React, { Component } from 'react';
// you should use ReactDOM.render instad of React.renderComponent
import ReactDOM from 'react-dom';

class ToggleBox extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // toggle box is closed initially
      isOpened: false,
    };
    // http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html
    this.toggleBox = this.toggleBox.bind(this);
  }

  toggleBox() {
    this.setState(oldState => ({ isOpened: !oldState.isOpened }));
  }

  render() {
    const { title, children } = this.props;
    const { isOpened } = this.state;
    return (
      <div className="box">
        <div className="boxTitle" onClick={this.toggleBox}>
          {title}
        </div>
        {isOpened && children && (
          <div className="boxContent">
            {children}
          </div>
        )}
      </div>
    );
  }
}

ReactDOM.render((
  <ToggleBox title="Click me">
    <div>Some content</div>
  </ToggleBox>
), document.getElementById('app'));

Демо: http://jsfiddle.net/kb3gN/16688/

Лучше визуализировать некоторый элемент только при необходимости, чем добавлять некоторые классы CSS с display: none. Если вы установите display: none - элемент по-прежнему визуализируется по реакции и добавляется в DOM - это может плохо повлиять на производительность.

Представьте, что у вас есть страница с вкладками, где на каждой вкладке много контента и только одна вкладка открывается одновременно. Гораздо лучше держать в DOM только те элементы, которые должны отображаться.

В приведенном выше коде, чтобы достичь этого, я использую такой код:

{opened && <SomeElement />}

Это будет оказывать SomeElement только если opened верно. Это работает из-за способа, которым JavaScript разрешает логические условия:

true && true && 2; // will output 2
true && false && 2; // will output false
true && 'some string'; // will output 'some string'
opened && <SomeElement />; // will output SomeElement if 'opened' is true, will output false otherwise
  • 2
    Это отличный пример! Одна маленькая вещь, boxContent должен быть className = "boxContent"
  • 2
    Демо-страница больше не работает
Показать ещё 3 комментария
15

с последней версией реагируют 0.11, вы также можете просто вернуть null, чтобы не отображал контент.

https://facebook.github.io/react/blog/2014/07/13/react-v0.11-rc1.html#rendering-to-null

10

Я создал небольшой компонент, который обрабатывает это для вас: https://www.npmjs.com/package/react-toggle-display

Он устанавливает атрибут стиля display: none !important на основе реквизитов hide или show.

Пример использования:

var ToggleDisplay = require('react-toggle-display');

var Search = React.createClass({
    getInitialState: function() {
        return { showResults: false };
    },
    onClick: function() {
        this.setState({ showResults: true });
    },
    render: function() {
        return (
            <div>
                <input type="submit" value="Search" onClick={this.onClick} />
                <ToggleDisplay show={this.state.showResults}>
                    <Results />
                </ToggleDisplay>
            </div>
        );
    }
});

var Results = React.createClass({
    render: function() {
        return (
            <div id="results" className="search-results">
                Some Results
            </div>
        );
    }
});

React.renderComponent(<Search />, document.body);
9

Вы устанавливаете логическое значение в состоянии (например, "показать" ), а затем выполните:

var style = {};
if (!this.state.show) {
  style.display = 'none'
}

return <div style={style}>...</div>
  • 0
    Я попробовал это, но событие click не переключило css в блок отображения. Я заблудился, как именно это сделать. Есть дополнительные советы?
  • 1
    Это включает внесение активных изменений в таблицу правил стиля. Гораздо лучше иметь одно существующее правило, которое вы можете включать и выключать, которое не является частью динамических свойств узла dom.
Показать ещё 4 комментария
7

Уже есть несколько отличных ответов, но я не думаю, что они были объяснены очень хорошо, и некоторые из приведенных методов содержат некоторые ошибки, которые могут вызвать людей. Поэтому я собираюсь пересмотреть три основных способа (плюс один вариант вне темы), чтобы сделать это и объяснить плюсы и минусы. Я в основном пишу это, потому что Вариант 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 довольно быстро создает компоненты с нуля. Тем не менее, он все равно должен вызывать ваш код при его создании. Поэтому, если ваш конструктор, компонентDidMount, рендеринг и т.д. Дорогой, то он значительно замедлит показ компонента. Это также означает, что вы не можете использовать это с компонентами с состоянием, в которых вы хотите сохранить состояние при скрытии (и восстанавливаться при отображении). Одно из преимуществ заключается в том, что скрытый компонент вообще не создается до его выбора. Таким образом, скрытые компоненты не будут задерживать вашу начальную загрузку страницы. Могут также быть случаи, когда вы хотите, чтобы компонент состояния был сброшен при переключении. В этом случае это ваш лучший вариант.

Вариант 2: Условный рендеринг у ребенка

Это создает оба компонента один раз. Затем замыкает остальную часть кода визуализации, если компонент скрыт. Вы также можете закорачивать другую логику другими способами, используя видимую опору. Обратите внимание на console.log на странице 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')
);

Теперь, если логика инициализации является быстрой и дети не имеют гражданства, то вы не увидите разницы в производительности или функциональности. Однако почему React создает абсолютно новый компонент, который все равно переключается? Если инициализация стоит дорого, Option 1 будет запускать ее каждый раз, когда вы переключаете компонент, который замедляет страницу при переключении. Вариант 2 будет запускать все компоненты для загрузки первой страницы. Замедление этой первой нагрузки. Следует отметить еще раз. Если вы просто показываете компонент один раз на основе состояния, а не переключая его, или вы хотите, чтобы он сбросился при переходе на него, то вариант 1 является прекрасным и, вероятно, лучшим вариантом.

Однако, если медленная загрузка страницы является проблемой, это означает, что у вас есть дорогой код в методе жизненного цикла, и это, как правило, не очень хорошая идея. Вы можете и, вероятно, должны решить медленную загрузку страницы, переместив дорогостоящий код из методов жизненного цикла. Переместите его в функцию async, которая была запущена компонентом ComponentDidMount, и обратный вызов помещает его в переменную состояния с помощью setState(). Если переменная состояния является нулевой и компонент виден, то функция рендеринга возвращает местозаполнитель. В противном случае выполните данные. Таким образом, страница будет быстро загружаться и заполнять вкладки при их загрузке. Вы также можете переместить логику в родительский элемент и подтолкнуть результаты к реквизитам. Таким образом, вы можете определить приоритеты, какие вкладки загружаются в первую очередь. Или кэшируйте результаты и запускайте логику при первом показе компонента.

Вариант 3: Скрытие класса

Скрытие класса, вероятно, проще всего реализовать. Как уже упоминалось, вы просто создаете класс CSS с отображением: none и назначаете класс на основе prop. Недостатком является весь код каждого скрытого компонента, и все скрытые компоненты привязаны к DOM. (Вариант 1 не создает скрытые компоненты вообще, а второй вариант замыкает ненужный код, когда компонент скрыт, и полностью удаляет компонент из DOM.) Похоже, что это происходит быстрее при переключении видимости в соответствии с некоторыми тестами, выполненными комментаторами на другие ответы, но я не могу с этим поговорить.

Вариант 4: Один компонент, но изменить реквизит. Или, может быть, нет компонента вообще и кэша HTML.

Это не будет работать для каждого приложения, и это не так, потому что оно не касается скрытия компонентов, но это может быть лучшим решением для некоторых случаев использования, чем скрытие. Скажем, у вас есть вкладки. Возможно, можно написать один компонент React и просто использовать реквизиты, чтобы изменить то, что отображается на вкладке. Вы также можете сохранить JSX в состояние переменных и использовать опору, чтобы решить, какой JSX будет возвращен в функции рендеринга. Если JSX должен быть сгенерирован, сделайте это и кешируйте его в родительском элементе и отправьте правильный в качестве опоры. Или сгенерируйте в дочернем устройстве и кешируйте его в дочернем состоянии и используйте реквизиты для выбора активного.

5

Это хороший способ использовать виртуальный DOM:

React:

            var Comp = React.createClass({
                getInitialState: function(){
                return {hide: false};
              },
              toggle: function(){
                this.setState({hide: !this.state.hide});
              },
              render: function() {
                return <div>
                        <button onClick={this.toggle}>toggle</button>    
                    <div className={'hide-' + this.state.hide}>Hi there</div>
                </div>;
              }
            });

            ReactDOM.render(
              <Comp />,
              document.getElementById('container')
            );

CSS

            .hide-true  {
              display: none;
            }

Скрипка здесь

  • 0
    Мне нравится этот скудный ответ. Жаль, что скрипка не убежит.
  • 1
    Обновлено: jsfiddle.net/daniloprates/aLd1w6qs/43
3
   class FormPage extends React.Component{
      constructor(props){
           super(props);
           this.state = {
             hidediv: false
           }
      }

     handleClick = (){
       this.setState({
          hidediv: true
        });
      }

      render(){
        return(
        <div>
          <div className="date-range" hidden = {this.state.hidediv}>
               <input type="submit" value="Search" onClick={this.handleClick} />
          </div>
          <div id="results" className="search-results" hidden = {!this.state.hidediv}>
                        Some Results
           </div>
        </div>
        );
      }
  }
3

Если вы хотите посмотреть, как TOGGLE отображать компонентную проверку этой скрипты.

http://jsfiddle.net/mnoster/kb3gN/16387/

var Search = React.createClass({
    getInitialState: function() {
        return { 
            shouldHide:false
        };
    },
    onClick: function() {
        console.log("onclick");
        if(!this.state.shouldHide){
            this.setState({
                shouldHide: true 
            })
        }else{
                    this.setState({
                shouldHide: false 
            })
        }
    },
render: function() {
    return (
      <div>
        <button onClick={this.onClick}>click me</button>
        <p className={this.state.shouldHide ? 'hidden' : ''} >yoyoyoyoyo</p>
      </div>
    );
}
});

ReactDOM.render( <Search /> , document.getElementById('container'));
2

Я начинаю с этого утверждения команды React:

В React вы можете создавать отдельные компоненты, которые инкапсулируют поведение тебе нужно. Затем вы можете отображать только некоторые из них, в зависимости от состояние вашего приложения.

Условный рендеринг в React работает так же, как условия работают в JavaScript. Использовать операторы JavaScript, такие как if или условные оператора для создания элементов, представляющих текущее состояние, и пусть Реагируйте обновление пользовательского интерфейса, чтобы соответствовать им.

В основном вам нужно показать компонент при нажатии кнопки, вы можете сделать это двумя способами, используя чистый React или используя CSS, используя чистый способ React, вы можете сделать что-то вроде кода ниже в вашем случае, поэтому в первом run, результаты не отображаются как hideResults is true, но, щелкнув по кнопке, состояние изменится, а hideResults - false, а компонент получит визуализацию снова с новыми условиями значения, это очень часто используется изменения вида компонентов в React...

var Search = React.createClass({
  getInitialState: function() {
    return { hideResults: true };
  },

  handleClick: function() {
    this.setState({ hideResults: false });
  },

  render: function() {
    return (
      <div>
        <input type="submit" value="Search" onClick={this.handleClick} />
        { !this.state.hideResults && <Results /> }
      </div> );
  }

});

var Results = React.createClass({
  render: function() {
    return (
    <div id="results" className="search-results">
      Some Results
    </div>);
   }
});

ReactDOM.render(<Search />, document.body);

Если вы хотите продолжить изучение условного рендеринга в React, посмотрите здесь.

2

Лучшая практика ниже в соответствии с документацией:

 {this.state.showFooter && <Footer />}

Отображать элемент только в том случае, если состояние действительно.

2

В некоторых случаях может оказаться полезным компонент более высокого порядка:

Создайте компонент более высокого порядка:

export var HidableComponent = (ComposedComponent) => class extends React.Component {
    render() {
        if ((this.props.shouldHide!=null && this.props.shouldHide()) || this.props.hidden)
            return null;
        return <ComposedComponent {...this.props}  />;
    }
};

Расширьте свой собственный компонент:

export const MyComp= HidableComponent(MyCompBasic);

Затем вы можете использовать его следующим образом:

<MyComp hidden={true} ... />
<MyComp shouldHide={this.props.useSomeFunctionHere} ... />

Это уменьшает бит шаблона и обеспечивает соблюдение соглашений об именах, однако, пожалуйста, помните, что MyComp все равно будет создан - способ опускать был упомянуто ранее:

{ !hidden && <MyComp ... /> }

0

Это также может быть достигнуто так (очень простой способ)

 class app extends Component {
   state = {
     show: false
   };
 toggle= () => {
   var res = this.state.show;
   this.setState({ show: !res });
 };
render() {
  return(
   <button onClick={ this.toggle }> Toggle </button>
  {
    this.state.show ? (<div> HELLO </div>) : null
  }
   );
     }
0

Если вы используете bootstrap 4, вы можете скрыть элемент таким образом

className={this.state.hideElement ? "invisible" : "visible"}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню