簡體   English   中英

React 中 UIkit 的模態:集成

[英]UIkit's modals in React: integration

我正在開發這個項目,其中前端與 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>
)

並在需要時以編程方式調用顯示/隱藏(甚至是 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())
      }
    )
  }
}

這似乎有效。 直到你離開一個組件。 當您回到它時,第二次以編程方式隱藏不再起作用。

任何人都可以引導我如何以更適合反應的方式集成這些部分?

使用操作dom(顯示,隱藏)的uikit部分顯然很難與React連接(可能你不應該),但是:

您需要通過傳遞模態狀態的bool(例如, modalopen )來移動函數show的調用並hide在Component內部。 一個好的鈎子是componentWillReceiveProps ,它可以用來檢查previus道具

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

(這是在Modal類中)

我不喜歡的東西絕對不是“React-way”,代碼是直接從動作創建者(!)變異狀態。 來自React docs

例如,不是在Dialog組件上公開open()和close()方法,而是將isOpen prop傳遞給它。

那么,如果你有一個由redux狀態控制的模態呢? 這是一個可能的實現:

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);

modal reducer它將公開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);

所以基本上你以redux action-creators的形式公開簡單的API來控制你的ModalWindow的狀態。 您可以在以后使用它:

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

當然,可能會有更多可選配置傳遞給動作創建者或隊列模態。

為此,我使用了鈎子和組件的組合。

鈎:

import { useState } from "react";
import UIkit from "uikit";

export default function useModal() {
  const [isOpen, setIsOpen] = useState(false);
  const [ref, setRef] = useState(null);

  const open = (e) => {
    UIkit.modal(ref).show();
    setIsOpen(true);
  };

  const close = (e) => {
    UIkit.modal(ref).hide();
    UIkit.modal(ref).$destroy(true);
    setIsOpen(false);
  };

  return [setRef, isOpen, open, close];
}

零件:

import React, { forwardRef } from "react";

const Modal = forwardRef(({ children, isOpen, full, close }, ref) => (
  <div
    ref={ref}
    data-uk-modal="container: #root; stack: true; esc-close: false; bg-close: false"
    className={`uk-flex-top ${full ? "uk-modal-container" : ""}`}
  >
    <div className="uk-modal-dialog uk-margin-auto-vertical">
      <button
        type="button"
        className="uk-modal-close-default"
        data-uk-icon="close"
        onClick={close}
      />
      {isOpen && children()}
    </div>
  </div>
));

export default Modal;

消耗:

function Demo() {
  const [ref, isOpen, open, close] = useModal();
  return (
    <div>
      <button
        type="button"
        className="uk-button uk-button-default"
        onClick={open}
      >
        upgrade
      </button>
      <Modal isOpen={isOpen} close={close} ref={ref} full>
        {() => (
          <div>
            <div className="uk-modal-header">
              <h2 className="uk-modal-title">title</h2>
            </div>
            <div className="uk-modal-body">
                body
            </div>
          </div>
        )}
      </Modal>
    </div>
  );
}

閱讀更多: https://reactjs.org/docs/integrating-with-other-libraries.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM