Модальные окна UIkit в React: интеграция

Я работаю над этим проектом, где интерфейс находится в React с UIkit для пользовательского интерфейса. Интеграция между частями выглядит плохо реализованной. Я объясню почему. Есть компонент Modal, что-то вроде

export class Modal extends Component {
  static getByName = name => UIkit.modal(`[data-modal-name='${name}']`)

  static show = name => {
    const modal = Modal.getByName(name)
    if (modal) modal.show()
  }

  static hide = name => {
    const modal = Modal.getByName(name)
    if (modal) modal.hide()
  }

  render() {
    // a modal
  }
}

это используется таким образом

export const LoginFormModal = props => (
  <Modal name = "login-form" className = "login-form-modal" hideClose>
    <LoginForm />
  </Modal>
)

и show / hide вызывается программно там, где это необходимо (даже действия redux)

Modal.hide("login-form")

это в действии Redux, например

export const login = credentials => {
  return dispatch => {
    dispatch(showLoader())

    API.authentication.login(
      credentials,
      response => {
        setCurrentUser(
          Object.assign({}, response.user, { user_id: response.user.id })
        )
        Modal.hide("login-form")
        dispatch(loginSucceded(response))
        dispatch(hideLoader())
        dispatch(push("/"))
        dispatch(fetchNotificationsCounter())
      },
      error => {
        dispatch(loginFailed(error))
        dispatch(hideLoader())
      }
    )
  }
}

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

Кто-нибудь может подсказать мне, как интегрировать части более соответствующим образом?

работает ли состояние redux с этим? Можете ли вы добавить образец кода с вашими действиями redux.

hendrathings 30.03.2018 04:00

В качестве примера добавлено действие redux

Ursus 30.03.2018 09:37

Работает с первого раза, мой модал закрыт программно. Но, если я оставлю компонент (отключен), я вернусь к нему, больше никогда не будет работать.

Ursus 30.03.2018 09:37

вы должны получить состояние, указывающее, что вы вошли в систему на LoginFormModal

hendrathings 30.03.2018 09:42
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
8
4
1 984
2

Ответы 2

Что мне не нравится, и это определенно не "способ реагирования", так это то, что код изменяет состояние непосредственно от создателя действия (!). От React docs:

For example, instead of exposing open() and close() methods on a Dialog component, pass an isOpen prop to it.

Так что, если бы у вас был один модальный файл, который контролировался бы состоянием редукции? Вот возможная реализация:

ModalWindow - будет реагировать на изменения состояния и рендерить в зависимости от того, что в магазине:

import React from 'react';
import InfoContent from './InfoContent';
import YesOrNoContent from './YesOrNoContent';
import { MODAL_ACTION } from './modal/reducer';

class ModalWindow extends React.Component {
  renderModalTitle = () => {
    switch (this.props.modalAction) {
        case MODAL_ACTION.INFO:
          return 'Info';
        case MODAL_ACTION.YES_OR_NO:
          return 'Are you sure?';
        default:
          return '';
    }
  };

  renderModalContent = () => {
    switch (this.props.modalAction) {
      case MODAL_ACTION.INFO:
        return <InfoContent />;
      case MODAL_ACTION.YES_OR_NO:
        return <YesOrNoContent />;
      default:
        return null;
    }
  };

  render() {
    return (
        this.props.isModalVisible ?
        <div>
           <p>{this.renderTitle()}</p> 
           <div>
              {this.renderModalContent()}
           </div>
        </div>
        :
        null
    );
  }
}

export default connect((state) => ({
    modalAction: state.modal.modalAction,
    isModalVisible: state.modal.isModalVisible,
}))(ModalWindow);

модальный редуктор он предоставит API для отображения / скрытия модального окна в приложении:

export const SHOW_MODAL = 'SHOW_MODAL';
export const HIDE_MODAL = 'HIDE_MODAL';

const INITIAL_STATE = {
  isModalVisible: false,
  modalAction: '',
};

export default function reducer(state = INITIAL_STATE, action) {
  switch (action.type) {
    case SHOW_MODAL:
      return { ...state, isModalVisible: true, modalAction: action.modalAction };
    case HIDE_MODAL:
      return { ...state, isModalVisible: false };
    default:
      return state;
  }
}

export const MODAL_ACTION = {
  YES_OR_NO: 'YES_OR_NO',
  INFO: 'INFO',
};

const showModal = (modalAction) => ({ type: SHOW_MODAL, modalAction });
export const hideModal = () => ({ type: HIDE_MODAL });
export const showInformation = () => showModal(MODAL_ACTION.INFO);
export const askForConfirmation = () => showModal(MODAL_ACTION.YES_OR_NO);

Таким образом, вы предоставляете простой API в виде создателей действий redux для управления состоянием вашего ModalWindow. Что вы можете позже использовать, например:

dispatch(showInformation())
...
dispatch(hideModal())

Конечно, это может быть что-то большее, например, дополнительная конфигурация, которая будет передана создателям действий или очередь для модальных окон.

Использование частей uikit, которые манипулируют dom (show, hide), очевидно, трудно соединить с React (и, вероятно, вам не следует этого делать), однако:

Вам нужно переместить вызов функций show и hide внутри компонента, передав логическое значение состояния модального окна (например, modalopen). Хороший крючок - componentWillReceiveProps, который можно использовать для проверки предыдущего реквизита.

componentWillReceiveProps(nextProps) {
  if (nextProps.modalopen !== this.props.modalopen) {
    if (nextProps.modalopen) {
      getByName(...).show()
    } else {
      getByName(...).hide()
    }
  }
}

(это внутри модального класса)

Вы, вероятно, делаете что-то подобное для своего загруженного (предположение основано на showLoader и hideLoader в диспетчере)

MaanooAk 05.04.2018 15:58

Другие вопросы по теме