Semantic-ui-react: как вызвать всплывающее окно без щелчка/наведения?

При отправке формы я хочу показать небольшое всплывающее окно на 2,5 секунды, если сервер отправляет неверный ответ.

Логика довольно проста, однако я не могу понять, как заставить это всплывающее окно прослушивать логическое значение где-то в управлении состоянием (в моем случае MobX). Я могу просто получить содержимое во всплывающем окне, однако триггер представляет собой кнопку (и содержимое будет отображаться, если вы нажмете на нее). Но как мне заставить его где-то прослушивать логическое значение?

Довольно простой класс здесь:

import React from "react";
import { Popup, Button } from "semantic-ui-react";
import { inject } from "mobx-react";
const timeoutLength = 2500;

@inject("store")
export default class ErrorPopup extends React.Component {

    state = {
        isOpen: false
    };

    handleOpen = () => {
        this.setState({
            isOpen: true
        });

        this.timeout = setTimeout(() => {
            this.setState({
                isOpen: false
            })
        }, timeoutLength)
    };

    handleClose = () => {
        this.setState({
            isOpen: false
        });
        clearTimeout(this.timeout)
    };

    render () {

        const errorContent = this.props.data;


        if(errorContent){
            return(
                <Popup
                    trigger={<Button content='Open controlled popup' />}
                    content={errorContent}
                    on='click'
                    open={this.state.isOpen}
                    onClose={this.handleClose}
                    onOpen={this.handleOpen}
                    position='top center'
                />
            )
        }
    }
}

Однако значением триггера является кнопка, которая отображается, если присутствует this.props.data. Но это не то поведение, которое я хочу; Я просто хочу, чтобы всплывающее окно отображалось (и, следовательно, срабатывало), если this.props.data есть; в качестве альтернативы я могу предоставить значение true с реквизитами, если это необходимо.

Но как мне заставить этот компонент срабатывать, не будучи наведением/кнопкой?


person cbll    schedule 08.06.2017    source источник
comment
Кажется, что реквизит open на самом деле является переходом к компоненту Portal (он используется Popup). Это также имеет смысл, почему закрыть его можно только таким образом. Когда вы передаете open=true, вы фактически передаете это Portal, однако компонент Popup позиционируется статически и, следовательно, не знает координат, в которых он должен находиться. Вот почему его можно открыть только через событие — они используют объект Event для получения позиции курсора. См. github.com/Semantic-Org/Semantic-UI-React/issues. /1065   -  person losnir    schedule 03.07.2017


Ответы (1)


Как насчет передачи реквизита isOpen? Затем вы можете добавить некоторую логику в хук componentWillReceiveProps:

import React from "react";
import { Popup, Button } from "semantic-ui-react";
import { inject } from "mobx-react";
const timeoutLength = 2500;

@inject("store")
export default class ErrorPopup extends React.Component {

 constructor(props) {
   super(props);
   this.state = {
     isOpen: false,
   }
 };

  //This is where you trigger your methods
  componentWillReceiveProps(nextProps){
    if(true === nextProps.isOpen){
      this.handleOpen();
    } else {
      this.handleClose();
    }
  }

  handleOpen = () => {

    this.setState({
      isOpen: true
    });

    this.timeout = setTimeout(() => {
      //No need to repeat yourself - use the existing method here
      this.handleClose();
    }, timeoutLength)
  };

  handleClose = () => {
    this.setState({
      isOpen: false
    });
    clearTimeout(this.timeout)
  };

  render () {

    const errorContent = this.props.data;

    if(errorContent){
      return(
        <Popup
          trigger={<Button content='Open controlled popup' />}
          content={errorContent}
          on='click'
          open={this.state.isOpen}
          position='top center'
        />
      )
    }
  }
}

Без необходимости обработки задержки - вы можете просто передать поддержку isOpen, и это сделает свое дело.

А вот как это может выглядеть при рендеринге вашего родительского компонента:

let isOpen = this.state.isOpen; 
<ErrorPopup isOpen={isOpen}/>

Установите это значение для управления всплывающим окном, в идеале оно должно быть частью состояния вашего родительского компонента. Наличие компонента с отслеживанием состояния в качестве родителя важно для повторного отображения всплывающего окна.

person Stas Parshyn    schedule 08.06.2017
comment
Я не совсем уверен, что вы решаете здесь? Основная проблема по-прежнему существует, когда срабатывание происходит по нажатию кнопки. - person cbll; 08.06.2017
comment
Нет, это не так. Вы просто передаете поддержку isOpen - и ваше всплывающее состояние обновляется соответствующим образом. Я уберу реквизиты onClose/onOpen из компонента Popup, если это вас смущает. - person Stas Parshyn; 08.06.2017
comment
Компонент, который вы показали здесь, насколько мне известно, даже не будет отображаться. А если on плюс trigger нет, то вообще ничего не отрендерится, даже если errorContent есть? - person cbll; 08.06.2017
comment
В качестве альтернативы вы сказали, что я могу предоставить истинную ценность с помощью реквизита, если это необходимо. - если вы предоставите это как значение props.isOpen - это будет работать нормально. Вот как вы слушаете логическое значение где-то в управлении состоянием - person Stas Parshyn; 08.06.2017
comment
Ну, да, но это все равно не решит основную проблему: запуск всплывающего окна полностью зависит от нажатия кнопки, что все еще имеет место? Кроме того, кажется, вы вызываете setState для опоры? Извините, если мой вопрос был сформулирован плохо, но я совершенно не понимаю, к чему вы клоните. - person cbll; 08.06.2017
comment
Я не уверен, как работает эта конкретная реализация всплывающего окна, но для большинства из них достаточно установить что-то вроде open={this.state.isOpen}, чтобы не использовать какие-либо обратные вызовы, управляемые событиями (например, нажатия кнопок и т. д.). Таким образом, ваша единственная забота должна заключаться в передаче правильного значения isOpen из родительского компонента. И да, мы запускаем изменение состояния с помощью хука смены реквизита. Чтобы сделать это полностью действительным - вы, вероятно, захотите запустить некоторые дополнительные проверки (если тайм-аут работает в данный момент и т. д.), но я лучше оставлю это на ваше усмотрение. - person Stas Parshyn; 08.06.2017
comment
Смотрите обновленный ответ, может быть, он прояснит ситуацию. - person Stas Parshyn; 08.06.2017
comment
Я полагаю, что понял суть и попробую, но вы вызываете setState в дочернем компоненте для того, что по сути должно быть реквизитом? В вашем примере логика не совсем верна, что меня немного смущает? Компонент, который вы написали, очевидно, не будет отображаться, вы устанавливаете isOpen в состояние, которое никогда не инициализируется (и, таким образом, оно вызовет ошибку). Кроме того, он по-прежнему запускается кнопкой (это то, что вы визуализируете вместо компонента), поэтому основная проблема остается почти такой же. - person cbll; 09.06.2017
comment
Точка неинициализированного состояния полностью действительна - я обновлю свой ответ фиксированным кодом, спасибо, что указали на это. Второй — загадочный. Вы говорите, что установка открытой опоры с true на false скроет всплывающее окно, но установка с false на true не покажет его? Надеюсь, что нет, потому что это не так. Посмотрите этот пример codepen.io/anon/pen/Mbxmyj. - person Stas Parshyn; 04.07.2017